ReaderWriterLockSlim对ThreadAbortException有抵抗力吗?

5

我想检查以下代码是否能够抵抗ThreadAbortException并且不会导致孤立锁。如果不能,那么在此处避免孤立锁的最佳模式是什么?

ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

public void DoStaff()
{
  _lock.EnterWriteLock();
  //Is this place where ThreadAbotException can corrupt my code, or is there JIT optimalization which prevent this from happening??? 
  try
  {
    ...
  }
  finally
  {
    _lock.ExitWriteLock();
  }
}

根据以下链接http://chabster.blogspot.cz/2013/07/a-story-of-orphaned-readerwriterlockslim.html,有可能(或者至少曾经有过)一种方式可以创建孤立锁,但我运行示例代码一段时间没有成功。

我正在使用.NET 4.0

在Debug和Release模式下的行为有什么区别吗?


更正 - 我是在打代码,而不是从源代码中复制 - 这就是那个错误的原因。 - user2126375
2个回答

4

是的,在这种情况下可能会发生ThreadAbortException,在这种情况下,try不会被执行,因此您永远不会退出写锁。

对于这个问题没有很好的通用解决方案。这就是为什么Eric Lippert(和其他人)说“锁和异常不能混合使用”。

您特别询问ThreadAbortException,这让我相信您正在考虑在应用程序中使用Thread.Abort进行某种线程控制。我敦促您重新考虑。如果您想要取消线程的能力,您应该使用Cancellation或类似的东西。在除了最紧急的情况之外使用Thread.Abort是一个非常糟糕的想法。它肯定不应该成为您程序的整体设计的一部分。


注意,如果你处理管理 AppDomains 的情况,ThreadAbort 就是需要关注的问题,因为它是运行时用来终止在被卸载的域中有代码的线程的方法。另一个常见情况是 ASP.Net 应用程序中的重定向,但使用 MVC 或非中止重载可以帮助解决这个问题。 - Alexei Levenkov
这是情况。我从未自己调用Thread.Abort。我担心系统 :-) - user2126375

1
为了使使用锁原语的代码在面对线程中止时更加健壮,需要确保每个获取锁和释放锁的请求都通过或者通过一个未共享的标记执行,该标记可以被赋予锁的“所有权”。根据锁定API的设计,标记可以是某个特定类型的对象、任意的Object或作为ref参数传递的变量。然而,必须在获取锁之前通过某种手段创建和存储标记,以便如果标记被创建但存储失败,可以轻松地放弃标记。不幸的是,尽管监视器锁已经添加了(在.NET 4.0中)使用ref bool作为标记的Monitor.EnterMonitor.TryEnter的重载,但我不知道是否有相应的读写锁。
如果需要实现可中止的读写锁功能,建议使用一个专门为此设计的类。该类应该跟踪持有读取或写入访问权限的线程,并且在等待锁被释放时,不应该依赖于线程来释放锁定,而是应该确保持有它的线程仍然活着。如果一个线程在持有读取权限时死亡,它应该被释放。如果一个线程在持有写入访问权限时死亡,则任何挂起或未来尝试获取锁定的尝试都应立即抛出异常。
否则,有一些技巧可以保护代码块免受Thread.Abort()的影响。不幸的是,我不知道如何以一种干净的方式将代码块围绕锁定请求括起来,以使得Abort能够在请求本身可以干净地中止而没有成功的情况下工作,但如果请求成功,则可以推迟Abort。
虽然有一些方法可以安全地允许一个无止境循环的线程被另一个线程终止,但设计可以安全使用的机制需要花费更多的精力,比Thread.Abort()更加复杂。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接