由于无法关闭数据库连接,线程被阻塞
Posted
技术标签:
【中文标题】由于无法关闭数据库连接,线程被阻塞【英文标题】:Threads are blocked due to unable to close database connection 【发布时间】:2013-03-06 17:30:24 【问题描述】:在堆栈跟踪中,MessageProcessor.Dispose()
、OnThreadShutdownRequested
和 RenewTaskLeaseCallback
都需要一个锁来防止这些对象中的竞争条件。
线程 (ID14968) 的堆栈跟踪保存了所有锁,这会导致其他线程阻塞并等待它释放锁。
问题在于,当在线程 14968 上调用 CloseConnection()
时,连接永远不会关闭,并且在 CloseConnection()
内部调用了 SyncAsyncLock.Wait()
。调用被阻塞,无法继续,出现死锁情况。
在调用CloseConnection()
时,什么可能导致线程阻塞?
更大的图像here。
【问题讨论】:
图片链接因权限无法访问。 对不起,我的权限设置有误,现已修复。 【参考方案1】:在解决这个问题两天后,我终于弄清楚了问题所在。 存在可能导致应用程序死锁的情况。
TaskLeaseRenewer
对象实现了IDisposable
,可以被多个线程访问。在类内部使用锁来确保没有两个线程会尝试同时释放对象。 TaskLeaseRenewer
有一个计时器和回调函数Callback
,它将由计时器在单独的线程上定期调用。 Callback
线程将尝试在创建TaskLeaseRenewer
的线程上调用Thread.Abort()
,并最终在TaskLeaseRenwer
上调用Dispose()
当我尝试中止执行以下操作的线程时会出现问题:
using(TaskLeaseRenewer renewer = new TaskLeaseRewnewer())
DoStuff();
我发现,当您在带有using
语句的线程上调用Thread.Abort()
时,它不会终止线程,直到它在使用的对象上调用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#
【讨论】:
以上是关于由于无法关闭数据库连接,线程被阻塞的主要内容,如果未能解决你的问题,请参考以下文章