この問題に2日間取り組んだ後、私はついに問題を理解しました。アプリケーションでデッドロックが発生する可能性がある状況がありました。
TaskLeaseRenewer
オブジェクトは実装されており、IDisposable
複数のスレッドからアクセスできます。クラス内でロックを使用して、2つのスレッドが同時にオブジェクトを破棄しようとしないようにします。タイマーと、別のスレッドでタイマーによって定期的に呼び出される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#