由于无法关闭数据库连接,线程被阻止

时间:2013-03-06 17:30:25

标签: c# sql multithreading concurrency deadlock

在堆栈跟踪中,MessageProcessor.Dispose()OnThreadShutdownRequestedRenewTaskLeaseCallback都需要锁定以防止这些对象中的竞争条件。 线程的堆栈跟踪(ID14968)保存所有锁,这会导致其他线程阻塞并等待它释放锁。

问题在于,当在线程14968上调用CloseConnection()时,连接永远不会关闭,SyncAsyncLock.Wait()CloseConnection()内部被调用。呼叫被阻止,不会继续,并发生死锁情况。

调用CloseConnection()时可能导致线程阻塞的内容是什么?

更大的图片herestacktrace of the deadlocked threads

1 个答案:

答案 0 :(得分:0)

在这个问题上工作了两天之后,我终于找到了问题所在。 有一种情况可能会导致应用程序陷入僵局。

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()函数试图获取的锁。 <{1}}将无法获取锁定,线程将永远不会终止。

解决此问题后,Dispose()死锁似乎消失了。我仍然对阻止连接关闭的原因感兴趣。

在更多地解决这个问题之后,我发现当一个线程被中止时,总是会调用一次性对象的connection.Close()对象。是否使用Dispose()语句。 Callstack如下:

using