ReaderWriterLockSlim LockRecursionPolicy.SupportsRecursion 死锁
ReaderWriterLockSlim LockRecursionPolicy.SupportsRecursion DeadLock
我有一个数据库写入操作队列,由一个专用线程管理。
而且我有很多线程可以随时从数据库中读取。
我正在使用 ReaderWriterLockSlim 进行 READ/WRITE 访问控制。
我的问题是——
为什么不推荐LockRecursionPolicy.SupportsRecursion? MSDN 文档说:
The use of recursion is not recommended for new development, because
it introduces unnecessary complications and makes your code more prone
to deadlocks.
这里怎么会死锁呢?例如,如果我在 WriteReadLock 已经获取时尝试调用 EnterReadLock(并且我在 SupportsRecursion 策略下)我得到一个异常...
锁递归是指在同一个线程上多次获取同一个锁而不离开原来的锁。
这方面的主要问题是,首先要进入那种情况,您可能对谁处理必要的同步有严重的问题 - 您的锁可能过于细化或过于全局。多线程很难,让它变得更难是彻头彻尾的蠢事。
第二个大问题是锁与线程绑定。但是,如果您正在编写异步代码,您的代码可能会随意地在不同的线程之间跳转,这可能意味着 看起来 的代码不是 -外部锁最终由与内部锁不同的线程拥有,线程 A 永远死锁等待线程 B 完成,而 B 正在等待 A 释放外部锁。
您提到 ReaderWriterLockSlim
即使在启用递归的情况下也会引发大量递归异常。是的,这意味着使用递归锁比使用递归锁更安全一点。 ReaderWriterLock
或 Monitor
。 MSDN 中清楚地概述了这些规则:
For a ReaderWriterLockSlim that allows recursion, the following can be said about the modes a thread can enter:
- A thread in read mode can enter read mode recursively, but cannot enter write mode or upgradeable mode. If it tries to do this, a LockRecursionException is thrown. Entering read mode and then entering write mode or upgradeable mode is a pattern with a strong probability of deadlocks, so it is not allowed. As discussed earlier, upgradeable mode is provided for cases where it is necessary to upgrade a lock.
- A thread in upgradeable mode can enter write mode and/or read mode, and can enter any of the three modes recursively. However, an attempt to enter write mode blocks if there are other threads in read mode.
- A thread in write mode can enter read mode and/or upgradeable mode, and can enter any of the three modes recursively.
- A thread that has not entered the lock can enter any mode. This attempt can block for the same reasons as an attempt to enter a non-recursive lock.
A thread can exit the modes it has entered in any order, as long as it exits each mode exactly as many times as it entered that mode. If a thread tries to exit a mode too many times, or to exit a mode it has not entered, a SynchronizationLockException is thrown.
他们尽最大努力彻底禁止几乎肯定会导致死锁的递归。然而,这并不意味着仍然没有被忽视的死锁(毕竟,您不需要递归来导致死锁——它只是给您很多难以找到的死锁机会)。更不用说在定期递归其锁的代码中很难做任何一致性保证——这可能意味着某些操作在从外部锁调用时是(半)原子的,但在直接调用它们时不再是原子的。
多线程已经够难了。不要仅仅因为你的对象设计被破坏就让它变得更难 :) Joe Albahari 的 "Threading in C#" 对多线程的一个很好的介绍(一般来说,特别是在 .NET 中),可以在互联网上免费获得(谢谢,乔!)。 ReaderWriterLockSlim
特别是在 http://www.albahari.com/threading/part4.aspx#_Reader_Writer_Locks
中处理
我有一个数据库写入操作队列,由一个专用线程管理。 而且我有很多线程可以随时从数据库中读取。
我正在使用 ReaderWriterLockSlim 进行 READ/WRITE 访问控制。
我的问题是—— 为什么不推荐LockRecursionPolicy.SupportsRecursion? MSDN 文档说:
The use of recursion is not recommended for new development, because it introduces unnecessary complications and makes your code more prone to deadlocks.
这里怎么会死锁呢?例如,如果我在 WriteReadLock 已经获取时尝试调用 EnterReadLock(并且我在 SupportsRecursion 策略下)我得到一个异常...
锁递归是指在同一个线程上多次获取同一个锁而不离开原来的锁。
这方面的主要问题是,首先要进入那种情况,您可能对谁处理必要的同步有严重的问题 - 您的锁可能过于细化或过于全局。多线程很难,让它变得更难是彻头彻尾的蠢事。
第二个大问题是锁与线程绑定。但是,如果您正在编写异步代码,您的代码可能会随意地在不同的线程之间跳转,这可能意味着 看起来 的代码不是 -外部锁最终由与内部锁不同的线程拥有,线程 A 永远死锁等待线程 B 完成,而 B 正在等待 A 释放外部锁。
您提到 ReaderWriterLockSlim
即使在启用递归的情况下也会引发大量递归异常。是的,这意味着使用递归锁比使用递归锁更安全一点。 ReaderWriterLock
或 Monitor
。 MSDN 中清楚地概述了这些规则:
For a ReaderWriterLockSlim that allows recursion, the following can be said about the modes a thread can enter:
- A thread in read mode can enter read mode recursively, but cannot enter write mode or upgradeable mode. If it tries to do this, a LockRecursionException is thrown. Entering read mode and then entering write mode or upgradeable mode is a pattern with a strong probability of deadlocks, so it is not allowed. As discussed earlier, upgradeable mode is provided for cases where it is necessary to upgrade a lock.
- A thread in upgradeable mode can enter write mode and/or read mode, and can enter any of the three modes recursively. However, an attempt to enter write mode blocks if there are other threads in read mode.
- A thread in write mode can enter read mode and/or upgradeable mode, and can enter any of the three modes recursively.
- A thread that has not entered the lock can enter any mode. This attempt can block for the same reasons as an attempt to enter a non-recursive lock.
A thread can exit the modes it has entered in any order, as long as it exits each mode exactly as many times as it entered that mode. If a thread tries to exit a mode too many times, or to exit a mode it has not entered, a SynchronizationLockException is thrown.
他们尽最大努力彻底禁止几乎肯定会导致死锁的递归。然而,这并不意味着仍然没有被忽视的死锁(毕竟,您不需要递归来导致死锁——它只是给您很多难以找到的死锁机会)。更不用说在定期递归其锁的代码中很难做任何一致性保证——这可能意味着某些操作在从外部锁调用时是(半)原子的,但在直接调用它们时不再是原子的。
多线程已经够难了。不要仅仅因为你的对象设计被破坏就让它变得更难 :) Joe Albahari 的 "Threading in C#" 对多线程的一个很好的介绍(一般来说,特别是在 .NET 中),可以在互联网上免费获得(谢谢,乔!)。 ReaderWriterLockSlim
特别是在 http://www.albahari.com/threading/part4.aspx#_Reader_Writer_Locks