C# 设置锁时线程关闭时锁会发生什么情况

C# 设置锁时线程关闭时锁会发生什么情况,c#,multithreading,locking,C#,Multithreading,Locking,我想知道,如果在一个线程中我有一个lock语句,并且如果在设置锁时关闭了特定的线程,那么锁会发生什么 其他线程是否有权访问关键区域(我的特定锁变量是否被解锁),或者锁是否保持活动并阻塞我的应用程序?如果是这样的话,我需要什么样的解决方案来避免砖块呢?在没有卸载应用程序域的情况下,您永远不应该从外部终止线程(例如Thread.Abort或更糟糕的原始winapi调用),所以这在实践中并不重要。要终止线程,请设置某种标志,线程检查该标志,然后正常退出 如果使用Thread.Abort将抛出一个异步异

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

其他线程是否有权访问关键区域(我的特定锁变量是否被解锁),或者锁是否保持活动并阻塞我的应用程序?如果是这样的话,我需要什么样的解决方案来避免砖块呢?

在没有卸载应用程序域的情况下,您永远不应该从外部终止线程(例如Thread.Abort或更糟糕的原始winapi调用),所以这在实践中并不重要。要终止线程,请设置某种标志,线程检查该标志,然后正常退出

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

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

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

声明:

lock (x)
{
    ...
}
由编译器在生成的IL中解释为:

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

因此,您可以看到,如果抛出异常,则会因为
finally
语句而释放锁。因此,即使您终止线程时使用了(这会导致在线程内部抛出一个)您绝对不应该执行的操作,锁也会被释放。

一个ThreadAbortException会被抛出,正如Darin所说,这将导致运行finally块来释放锁

但是


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

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

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


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

您所说的“线程已关闭”是什么意思?正常退出,引发异常,调用.NET
Thread.Abort
,调用Win32
TerminateThread
,或者其他什么?Thread.Abort或引发异常exception@BadescuAlexandruNOP表示无操作,或“无操作”,这是一条指令,通常不执行任何操作这只是在调试中编译时的问题,因为编译器生成NOP以便于调试。在版本中编译不会生成NOP指令。请看:实际上,这不再是生成的真实代码,因为它不安全。问题是调用
监视器时可能会引发
ThreadAbortException
。在获取锁之前或之后,以及在
try
/
最后
块作用域之前,输入
。这就是为什么自C#4以来,C#编译器不再使用
Monitor.Enter(object)
。见答案