【问题标题】:ReaderWriterLockSlim how to wait to enter lock?ReaderWriterLockSlim 如何等待进入锁?
【发布时间】:2015-05-14 22:25:29
【问题描述】:

我正在尝试使用 ReaderWriterLockSlim 以这样的异步方法锁定一些数据库工作:

readerWriterLock.EnterWriteLock();
using (var db = new MyContextDB())
{
    // look something up and alter it
}
readerWriterLock.ExitWriteLock();

这会引发异常,因为多个线程同时尝试进入 writelock。现在我可以使用锁定对象,但我想我会使用 ReaderWriterLockSlim,这样我就可以尝试通过读/写和可升级进行一些优化。

ReaderWriterLockSlim 的 MSDN 示例让我有些困惑。有没有一种简单的方法让线程等待锁变得可用? IsWriteLockHeld 属性表示它只是测试当前线程是否被锁定。 WaitingWriteCount 表示它给出了等待进入的线程数,但是如何让线程等待进入?我在任何样品中都找不到。我的意思是循环直到它不抛出异常?这似乎不对。

【问题讨论】:

  • 首先为什么要为局部变量加锁?
  • 这会引发异常,因为多个线程同时尝试进入 writelock。 这应该不会导致异常。您能否提供完整的示例来展示所描述的行为?
  • 我在类构造函数中声明了锁。我应该在每个线程中声明吗?那么如何为多个数据库分组锁呢?
  • "这会引发异常,因为多个线程同时尝试进入 writelock。"不,它没有。导致异常的原因是另一回​​事。你得到了什么例外?
  • 递归锁异常

标签: c# multithreading asynchronous async-await


【解决方案1】:

您在评论中说您得到的异常是LockRecursionException

这意味着某处:

  1. 一个线程正在访问EnterWriteLock,而那个线程已经有一个写锁,并且锁不是用LockRecursionPolicy.SupportsRecursion创建的。不要用LockRecursionPolicy.SupportsRecursion 创建它;递归锁总是一个坏主意;解决您正试图获得已经拥有的锁的事实。 (更多关于锁递归不好的原因在https://stackoverflow.com/a/12014173/400547的答案中讨论)。

  2. 当线程具有读锁时,它正在命中EnterWriteLock。先释放读锁。

有一些包含/排他锁(AKA“读取器/写入器锁”)允许代码在已经拥有读取锁时获得写入锁。正如https://stackoverflow.com/a/8807232/400547 的答案中所解释的那样,这可能会导致严重的死锁,所以幸运的是ReaderWriterLockSlim 不支持这一点。首先释放您的读卡器锁,或使用可升级的锁。

或者实际上,由于所涉及的工作涉及数据库,因此只需使用事务并让数据库处理并发问题。

【讨论】:

  • 你是对的,我在部分代码中遇到了一个不相关的异常,并且 catch/finally 没有释放锁。我更新了它,现在它工作正常。谢谢您的帮助。真的很感激
  • 我喜欢将这样的锁访问封装在一次性对象中,Enter 用于构造,Exit 用于处置,以便using 防止此类问题发生。也就是说,由于您的包装是数据库工作,因此事务可能是一个更好的整体解决方案。
  • 顺便说一句,你得到的错误是一个很好的例子,说明为什么允许递归是不好的;如果您的锁支持递归,那么您将在Exit 上等待线程而不是得到异常,这不会永远发生,这对于调试来说要复杂得多。
  • 好主意!我会采用这种模式
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-23
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多