ReaderWriterLockSlim LockRecursionPolicy.SupportsRecursion DeadLock

时间:2016-06-09 08:23:54

标签: c# multithreading readerwriterlockslim

我有一个数据库写入操作队列,由一个专用线程管理。 我有很多线程可以随时从数据库中读取。

我使用ReaderWriterLockSlim进行READ / WRITE访问控制。

我的问题是 - 为什么不建议使用LockRecursionPolicy.SupportsRecursion? MSDN文档说:

  

不推荐在新开发中使用递归,因为   它引入了不必要的复杂性,使您的代码更容易出错   死锁。

如何在这里实现僵局?例如,如果我在WriteReadLock已经获得时尝试调用EnterReadLock(并且我在SupportsRecursion策略下),我会得到一个异常......

1 个答案:

答案 0 :(得分:2)

锁定递归是指在同一个线程上多次执行相同的锁定而不离开原始锁定。

这个问题的主要问题是,为了首先处理这种情况,你可能会遇到严重的问题,谁处理必要的同步 - 你的锁可能过于细化,或者过于全局。多线程是很难的,而且更难以实现更多的线索。

第二个重要的事情是锁与线程相关联。但是,如果您正在编写异步代码,那么您的代码可能会在不同的线程之间跳转,这可能意味着出现的代码正在进行递归锁定 - 不是 - 外部锁最终由一个不同于内部锁的线程拥有,并且你永远与线程A死锁,等待线程B完成,而B正在等待A释放外部锁。

你提到即使启用了递归,ReaderWriterLockSlim也会抛出很多递归异常。是的,这意味着使用递归锁定比处理例如处理锁定时更安全一些。 ReaderWriterLockMonitor。 MSDN中明确列出了这些规则:

  

对于允许递归的ReaderWriterLockSlim,可以说以下关于线程可以输入的模式:

     
      
  • 处于读取模式的线程可以递归进入读取模式,但不能进入写入模式或可升级模式。如果它尝试执行此操作,则抛出LockRecursionException。进入读取模式然后进入写入模式或可升级模式是一种具有很强的死锁概率的模式,因此不允许这样做。如前所述,可以在需要升级锁的情况下提供可升级模式。
  •   
  • 处于可升级模式的线程可以进入写入模式和/或读取模式,并且可以递归地进入三种模式中的任何一种。但是,如果其他线程处于读取模式,则尝试进入写入模式。
  •   
  • 处于写入模式的线程可以进入读取模式和/或可升级模式,并可以递归方式进入三种模式中的任何一种。
  •   
  • 未进入锁定的线程可以进入任何模式。此尝试可能会阻止与尝试输入非递归锁定相同的原因。
  •   
     

线程可以按任何顺序退出它输入的模式,只要它退出每个模式的次数与进入该模式的次数完全相同。如果某个线程尝试多次退出某个模式,或者为了退出一个尚未进入的模式,则抛出SynchronizationLockException。

他们尽力彻底禁止递归,这几乎可以保证导致死锁。然而,这并不意味着仍然没有被忽视的死锁(毕竟,你不需要递归来导致死锁 - 它只是给你很多难以找到死锁的机会) 。更不用说在常规处理其锁定的代码中执行任何一致性保证是非常困难的 - 这可能意味着某些操作在从外部锁定调用时是(半)原子的,但在它们&#时不再是# 39;直接调用。

多线程很难实现。不要仅仅因为你的对象设计被打破而变得更难:)多线程的一个很好的介绍(特别是在.NET中)是Joe Albahari"在C#中的线程#&# 34;,免费在互联网上提供(谢谢,乔!)。 ReaderWriterLockSlim特别是在http://www.albahari.com/threading/part4.aspx#_Reader_Writer_Locks

中处理