【问题标题】:what happens with lock when thread gets closed while the lock is set设置锁时线程关闭时锁会发生什么
【发布时间】:2010-11-21 19:23:18
【问题描述】:

我想知道,如果在一个线程中我有一个锁语句,并且如果在设置锁时该特定线程被关闭,那么锁会发生什么?

其他线程是否可以访问临界区(我的特定锁变量是否被解锁)或者锁是否保持活动状态并阻塞我的应用程序?如果是这样,我有什么解决方案来避免砖头?

【问题讨论】:

  • “该线程已关闭”是什么意思?正常退出,抛出异常,调用 .NET Thread.Abort,调用 Win32 TerminateThread,还是别的什么?
  • Thread.Abort 或抛出异常

标签: c# multithreading locking


【解决方案1】:

lock 声明:

lock (x)
{
    ...
}

由编译器在生成的 IL 中解释为:

Monitor.Enter(x);
try 
{
   ...
}
finally 
{
   Monitor.Exit(x);
}

所以你可以看到如果抛出异常,锁是因为finally语句而被释放的。因此,即使您使用Thread.Abort 终止线程(这会导致在线程内抛出ThreadAbortException),您应该绝对不要这样做,锁也会被释放。

【讨论】:

  • 实际上,这不再是生成的真实代码,因为它不安全。问题是ThreadAbortException 可以在调用Monitor.Enter 期间、获取锁之前或之后以及try/finally 块范围之前引发。这就是为什么自 C# 4 以来 C# 编译器不再使用 Monitor.Enter(object) 的原因。请参阅 stackoverflow.com/questions/2837070/… 的答案
【解决方案2】:

一个 ThreadAbortException 被抛出,正如 Darin 上面所说的那样,大部分时间都会导致 finally 块被运行,这将释放锁。

但是……

在某些情况下,这不会发生。其中最常见的是编译器在 try 和 finally 之间插入 NOP。如果发生这种情况并且在该特定时间点发生异常,则锁将成为孤立锁,从而导致死锁场景。

【讨论】:

  • @BadescuAlexandru NOP 表示无操作或“无操作”,即(通常)什么都不做的指令en.wikipedia.org/wiki/NOP
  • 这只会在 Debug 中编译时出现问题,因为编译器会生成 NOP 以便于调试。在发行版中编译不会生成 NOP 指令。见:stackoverflow.com/a/13752156/1919294
【解决方案3】:

您永远不应该从外部终止(例如 Thread.Abort 或更糟糕的原始 winapi 调用)线程而不卸载应用程序域,因此这在实践中并不重要。要终止线程,请设置某种标志,线程会检查该标志,然后优雅地退出。

如果你使用Thread.Abort 会抛出一个异步异常,因此如果在finally 子句中释放了锁(lock 语句就是这种情况),那么锁将被清除。但是异步异常很容易破坏状态,除非代码已经仔细考虑过它们,所以应该避免它们。

MSDN on ThreadAbortException:

当调用 Abort 方法来销毁线程时,公共语言运行时会引发 ThreadAbortException。 ThreadAbortException 是一个可以被捕获的特殊异常,但它会在 catch 块结束时再次自动引发。引发此异常时,运行时会在结束线程之前执行所有 finally 块。因为线程可以在 finally 块中进行无限计算或调用 Thread.ResetAbort 来取消中止,所以不能保证线程将永远结束。如果要等到中止的线程结束,可以调用 Thread.Join 方法。 Join 是一个阻塞调用,直到线程真正停止执行才返回。

如果您使用原始 winapi 中止线程,那么您很不走运,也应该终止该进程。

【讨论】:

    【解决方案4】:

    获取锁的唯一原因是您可以更改对象的状态,而不会让其他线程看到它处于无效状态。如果在状态恢复到有效之前强制释放该锁,则下一个获取锁的线程将在访问不一致状态时崩溃。

    例如,考虑一下双向链表中的指针。如果关闭的线程修改了前向指针但没有修改相应的后向指针怎么办?如果您没有干净地关闭螺纹的代码,那么无论锁是否自动释放,您都会被拧紧。 (如果被释放了,下一个获取它的线程会在访问坏指针时炸掉。如果没有释放,每个试图获取它的线程都会挂起。)

    如果你确实有代码干净地关闭线程,那么它肯定也会释放锁。因此,如果这是您的问题,那么您做错了其他事情。

    【讨论】:

      猜你喜欢
      • 2011-03-28
      • 2010-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-06
      • 1970-01-01
      相关资源
      最近更新 更多