TPLを使用して、実行時間の長いタスクをスレッドプールにキューに入れています。一部のタスクはしばらくの間ブロックされる可能性があるため、次のパターンを使用してそれらをキャンセルしています。
private void RunAction(Action action, CancellationTokenSourceWithException cts)
{
try
{
s_logger.Info("Starting action on thread ID: {0}", Utils.GetCurrentNativeThreadId());
Thread taskThread = Thread.CurrentThread;
cts.Token.Register(() => InterruptTask(taskThread));
s_logger.Info("Running next action");
action();
}
catch (Exception e)
{
cts.Cancel(e);
throw;
}
このように呼び出すcts.Cancel()
と、タスクスレッドがブロックされている場合に、タスクスレッドが中断されます。ただし、これにより問題が発生しました。スレッドが実際にThreadInterruptedExceptionを取得したかどうかはわかりません。それを呼び出すことは可能ですThread.Interrupt()
が、スレッドは完了するまで実行され、タスクは単に終了します。その場合、スレッドプールスレッドにはThreadInterruptedExceptionの形式のカチカチ音をたてる爆弾があり、別のタスクがこのスレッドで実行されてブロックしようとすると、この例外が発生します。
Thread.ResetInterrupted()
ここでは(と同様の)方法がThread.ResetAbort()
役立ちますが、存在しないようです。次のようなものを使用できます。
try
{
someEvent.Wait(10);
}
catch (ThreadInterruptedException) {}
ThreadInterruptedExceptionを飲み込みますが、見た目は醜いです。
誰かが代替案を提案できますか?スレッドプールスレッドでThread.Interruptを呼び出すのは間違っていますか?タスクをキャンセルする最も簡単な方法のようです。イベントなどを使用した協調キャンセルは、使用するのがはるかに面倒であり、タスクから使用するすべてのクラスに伝播する必要があります。