我想知道,如果在一个线程中我有一个锁定语句并且如果在设置锁定时该特定线程被关闭,那么锁定会发生什么?
其他线程是否可以访问关键区域(我的特定锁定变量是否已解锁)或者锁定是否仍然处于活动状态并且会阻止我的应用程序?如果是这样,我有什么解决方案可以避免砖?
答案 0 :(得分:12)
lock声明:
lock (x)
{
...
}
由编译器在生成的IL中解释为:
Monitor.Enter(x);
try
{
...
}
finally
{
Monitor.Exit(x);
}
因为您可以看到是否抛出了异常,因为finally
语句释放了锁。因此,即使您使用Thread.Abort终止线程(这会导致ThreadAbortException被抛入线程内),您应该绝对不会这样做,锁定将被释放。< / p>
答案 1 :(得分:3)
抛出一个ThreadAbortException,大部分时间如上面的Darin所说,将导致finally块被运行,这将释放锁。
但是...
有些情况下不会发生这种情况。最常见的是如果在try&amp; amp;之间插入NOP。最后由编译器完成。如果发生这种情况并且在该特定时间点发生异常,则锁将变为孤立状态,从而导致死锁情况。
查看http://www.bluebytesoftware.com/blog/PermaLink.aspx?guid=f9a1d4c8-553b-4cc1-b1d6-0a8c395d8e9c以获得比我能给出的更好的解释
答案 2 :(得分:1)
你永远不应该从外部终止(例如Thread.Abort甚至更糟糕的原始winapi调用)线程而不卸载app-domain,所以这在实践中无关紧要。要终止线程,请设置线程检查然后正常退出的某种标志。
如果使用Thread.Abort
,则会抛出异步异常,因此如果在finally子句中释放锁,则会清除锁(这是lock
语句的情况)。但异步异常很容易破坏状态,除非代码已经仔细考虑过它们,所以应该避免它们。
当调用Abort方法来销毁线程时,公共语言运行库会抛出ThreadAbortException。 ThreadAbortException是一个可以捕获的特殊异常,但它会在catch块的末尾自动再次引发。引发此异常时,运行时会在结束线程之前执行所有finally块。因为线程可以在finally块中执行无限制计算或调用Thread.ResetAbort来取消中止,所以无法保证线程将永远结束。如果要等到中止的线程结束,可以调用Thread.Join方法。 Join是一个阻塞调用,在线程实际停止执行之前不会返回。
如果您使用原始的winapi来中止某个帖子,那么您将非常幸运,并且也应该终止该过程。
答案 3 :(得分:0)
关于获取锁定的唯一原因是,您可以更改对象的状态,而不让其他线程看到它处于无效状态。如果在状态恢复为有效之前强行释放该锁,则在访问不一致状态时,获取锁的下一个线程将会爆炸。
例如,想想双链表中的指针。如果关闭的线程修改了前向指针但没有修改相应的后退指针怎么办?如果您没有干净地关闭线程的代码,那么无论锁是否自动释放,您都会被搞砸。 (如果它被释放,下一个获取它的线程会在访问破坏的指针时爆炸。如果没有释放,每个试图获取它的线程都会挂起。)
如果你确实有代码来干净地关闭线程,那么它肯定也会解除锁定。所以如果这是你的问题,那你就做错了。