8

MSDN 文档和许多使用ReaderWriterLockSlim类的示例建议使用以下模式:

cacheLock.EnterWriteLock();
try
{
    //Do something
}
finally
{
    cacheLock.ExitWriteLock();
}

但我很好奇它是否完全安全。是否有可能在获取锁之后,但在语句之前发生一些异常,try从而使锁卡在锁定状态?最明显的候选人是ThreadAbortException。我知道这种情况发生的可能性非常小,但后果非常糟糕——所以我认为值得考虑。我不相信编译器理解这种模式并防止处理器在try语句之前中断线程。

如果理论上有这种代码不安全的可能性,有没有办法让它更安全?

4

2 回答 2

8

我能想到的理论上只有三种方式可能会失败:

  • ThreadAbortException你已经提到了。这很容易正确处理:只要确保你从不调用Thread.Abort(). 您几乎可以肯定不需要;几乎总是有更好的方法来达到预期的结果。

    当您真的,真的,真的需要调用它,并且您要中止的线程是有保持锁打开风险的线程时,请将您的整个代码块(从Enterto Exit)放在try...finally子句中尝试块为空。只有在当前处理程序完成时Thread.Abort()才会抛出。ThreadAbortExceptionfinally

  • StackOverflowException是另一种可能。它可能发生在调用ExitWriteLock. 这也相当简单:当发生堆栈溢出时,进程终止。你无法捕捉或处理它。由于该进程已终止,因此您的进程中没有其他线程将保持任何锁处于打开状态。

  • OutOfMemoryException理论上可能会在调用ExitWriteLock. 与 不同StackOverflowException的是,这个理论上是可以捕获的。如果你没有抓住它,进程将再次被终止,并且你的进程中没有其他线程将保持任何锁打开。但是,如果你确实抓住了它,你就不能希望正确地处理它,而且很可能你的其他线程很快也会开始抛出这个异常。

简而言之,我不会担心它。

于 2014-07-02T14:15:29.420 回答
7

这可能是一个问题,显然是在某些高负载情况下。本文将进一步深入,但基本上归结为使用空的 try 块加上 finally 来获取和释放锁:

var lockIsHeld = false;
try {
   try {
   }
   finally {
      rwl.EnterReadLock();
      lockIsHeld = true;
   }

   // Do work here
}
finally {
   if (lockIsHeld) {
      rwl.ExitReadLock();
   }
}

这种方法保证你的锁总是被获取和释放,因为即使在ThreadAbortException.

@hvd 的帖子中详细介绍了其他例外情况。

除非你真的在野外看到这个问题,否则我个人不会担心......

于 2014-07-02T14:21:13.487 回答