在这个问题上工作了两天后,我终于弄清楚了问题所在。有一种情况可能导致应用程序出现死锁。
该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#