在这个问题上工作了两天后,我终于弄清楚了问题所在。有一种情况可能导致应用程序出现死锁。
该TaskLeaseRenewer
对象实现IDisposable
并且可以被多个线程访问。在类内部使用锁来确保没有两个线程会尝试同时释放对象。TaskLeaseRenewer
有一个定时器和一个回调函数Callback
,定时器将在一个单独的线程上定期调用。Callback
线程将尝试调用Thread.Abort()
创建TaskLeaseRenewer
并最终调用Dispose()
的线程TaskLeaseRenwer
当我尝试中止执行以下操作的线程时,就会出现问题:
using(TaskLeaseRenewer renewer = new TaskLeaseRewnewer())
{
DoStuff();
}
我发现当你Thread.Abort()
用语句调用线程时using
,它不会终止线程,直到它调用Dispose()
所用对象上的函数。
下面的示例将ConnectionWrapper.Dispose()
在线程中止之前触发。
static void DisposeOnAbort()
{
Thread t = new Thread(() =>
{
Console.WriteLine("Using connection wrapper");
using (ConnectionWrapper wrapper = new ConnectionWrapper())
{
while (true)
{
Thread.Sleep(1000);
}
}
});
t.Start();
Thread.Sleep(1000);
Console.WriteLine("Aborting thread..");
t.Abort();
}
鉴于这些,我发现问题是当Callback()
调用时Thread.Abort()
,TaskLeaseRenewer.Dispose()
将在它创建的线程上调用,因为线程正准备被杀死。但是Callback()
,函数位于不同的线程上,并且还持有该Dispose()
函数试图获取的锁。Dispose()
将无法获得锁,并且线程永远不会终止。
解决了这个问题后,connection.Close()
僵局似乎消失了。我仍然对可能阻止连接关闭的原因感兴趣。
在更多地解决这个问题之后,我发现当一个线程被中止时,一次性对象的Dispose()
对象总是被调用。是否using
使用语句。调用栈如下:
Threads.exe!Threads.ConnectionWrapper.Dispose() Line 150 C#
Threads.exe!Threads.Program.DisposeOnAbort.AnonymousMethod__0() Line 58 + 0x2c bytes C#