【问题标题】:Is it ok (avoids deadlocks, starvations, etc...) to try acquire a lock in a loop with a sleep?是否可以(避免死锁、饥饿等)尝试在具有睡眠的循环中获取锁?
【发布时间】:2011-06-14 23:59:37
【问题描述】:

我正在使用 ReaderWriterLock 类来锁定作为 SortedDictionary 的 Quotes 集合。我正在考虑使用 while 循环,直到线程可以获取读取器锁,以防它被临时锁定以进行写入。第一个问题,我的测试运行良好,但是这种方法有缺点吗?第二个问题,这样做的最佳/最佳实践方式是什么?

        public void RequestQuote(string symbol, QuoteRequestCallback qrc)
        {
            // add the call back on a list and take care of it when the quote is available
            while (!AcquireReaderLock(100)) Thread.Sleep(150);
            if (Quotes.ContainsKey(symbol))
            {
                qrc(Quotes[symbol]);
                rwl.ReleaseReaderLock();
            }
            else
            {
                rwl.ReleaseReaderLock();
                lock (requestCallbacks)
                    requestCallbacks.Add(new KeyValuePair<string, QuoteRequestCallback>(symbol, qrc));
                // request symbol to be added
                AddSymbol(symbol);
            }
        }


        private bool AquireReaderLock(int ms)
        {
            try
            {
                rwl.AcquireReaderLock(ms);
                return true;
            }
            catch (TimeoutException)
            {
                return false;
            }
        }

        private bool AquireWriterLock(int ms)
        {
            try
            {
                rwl.AcquireWriterLock(ms);
                return true;
            }
            catch (TimeoutException)
            {
                return false;
            }
        }

【问题讨论】:

  • 如果 AcquireReaderLock 永远不会返回 true 会怎样?你的程序是否保持一致的状态?
  • 如果 AcquireReaderLock 永远不会返回 true,则 RequestQuote 将陷入无限循环。我还要在编辑中粘贴它的代码。
  • 好吧,我的意思是你不能假设它会。因此,如果超出了一定的重试次数,您需要一些机制来打破等待循环。
  • 我明白了。说得通。因此,经过多次重试后,我会向请求程序集发送异常。

标签: c# .net multithreading deadlock


【解决方案1】:

在使用AcquireReaderLock() 方法锁定之前,您是否有第二段密码锁定requestCallbacks?如果是这样,它可能会因此而死锁。

添加循环和睡眠延迟以避免死锁在一般情况下不起作用。严格的hierarchy of lock acquisition 在一般情况下工作。

【讨论】:

  • 不,我没有 requestCallbacks 与 AcquireReaderLock 同时被锁定。你能举一个严格层次结构的例子吗?你失去了我。
  • @Behrooz,我添加了一个链接,指向锁层次结构的体面描述;基本上,您要确保始终其他类型的锁之前获得某些锁(或某种锁),并以相反的顺序释放它们。你可以决定你总是先锁定你的回调,然后是你的报价(或相反);或者您可以决定按照最低指针值的顺序锁定您的资源;或者,如果锁竞争激烈,也许只需用一个替换两个锁,这样就可以避免死锁。
  • @Behrooz,但如果这是整个系统中唯一同时锁定这两个锁的代码,那么您可能已经完成了。 :)
【解决方案2】:

我不太明白你想达到什么目的。 ReaderWriterLockSlim(我会使用它)已经毫不费力地表现得那样 - 不需要额外的旋转,你只是在浪费资源。 a) 如果符号未找到或更好,则将 R-Lock 提升为 W-Lock,将 R 和 W 访问分离到不同的方法中。 b) 不要提供从受保护部分内部调用未知代码的可能性

public void RequestQuote(string pS, QuoteRequestCallback pQrc) {
    Quote tQ;
    // acquire/release ReadLock inside TryGet
    if (TryGetQuote(pS, out tQ)) {
        pQrc(tQ);
    } else {
        // acquire/release WriteLock inside AddQuote
        // remark: I left the other collection
        // out since it seems unrelated to the actual problem
        AddQuote(new KeyValuePair(...)); // as above
    }
}

【讨论】:

  • 我不知道 ReaderWriterLockSlim。阅读它并改变我的实现。效果很好。谢谢
  • 嗯,它们在概念上并没有什么不同,只是逻辑上相同事物的更好、更有效的实现。其他备注更重要...
猜你喜欢
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-13
  • 2020-09-14
  • 1970-01-01
相关资源
最近更新 更多