Thread.AbortメソッドとThread.Interruptメソッドの2セント
C#では、ブロックされたスレッドを解放する必要がある場合があります。これを実現するには、2つの方法を利用できます。これらには、Thread.AbortメソッドとThread.Interruptメソッドが含まれます。
Thread.Abortメソッドは何をしますか?
スレッドを終了するには、ThreadクラスのAbortメソッドを利用できます。スレッドを終了するプロセスを開始するために、ThreadクラスのAbortメソッドが呼び出されると、呼び出されたスレッドでThreadAbortExceptionが発生することに注意してください。 ThreadクラスのAbortメソッドを利用して、ブロックされていないスレッドでも終了できることに注意してください。中断されているスレッドが待機状態にある場合、スレッドはそれをウェイクアップしてから、ThreadInterruptedExceptionをスローします。同様に、待機状態のスレッドでThread.Abortメソッドを呼び出すと、ランタイムはスレッドをウェイクアップしてからThreadAbortExceptionをスローします。
catchブロックでThreadAbortExceptionをキャッチできます。ただし、ResetAbortメソッドを呼び出さない場合、この例外はcatchブロックの最後で再スローされます。ResetAbortメソッドを呼び出すと、catchブロックの最後でThreadAbortExceptionが再スローされるのを防ぐことができます。Thread.Inturruptメソッドの動作とは逆に、Thread.Abortメソッドが呼び出されたスレッドがブロックされていない場合、Thread.AbortメソッドはスレッドにThreadAbortExceptionをスローします。
ほとんどの場合(スレッドが中止された後にアプリケーションドメインをシャットダウンしたい場合を除いて)、このメソッドを使用する必要はまったくありません。ASP.NetのResponse.RedirectメソッドはThreadAbortExceptionをスローすることに注意してください。
Thread.Interruptメソッドの目的は何ですか?
Thread.Interruptメソッドを使用して、WaitSleepJoin状態のスレッドに割り込むことができます。ただし、これらのアプローチ(Thread.AbortまたはThread.Interruptメソッド呼び出し)はいずれもスレッドセーフではありません。 Thread.AbortメソッドがThreadAbortExceptionをスローするのに対し、Thread.InterruptメソッドはThreadInterruptExceptionをスローします。基本的に、Thread.Interruptメソッドの呼び出しはスレッドを中断し、ThreadInterruptedExceptionをスローして、ブロッキング呼び出し内のスレッドを中断します。コードでこの例外を処理する必要があります。失敗すると、ランタイムはThread.Interruptメソッドが呼び出されたスレッドを停止します。 Thread.Interruptを呼び出しても、アンマネージコードを実行しているスレッドは中断されないことに注意してください。
Thread.Interruptメソッドを強制的に呼び出してスレッドを中断する方法を示す次のコードリストについて考えてみます。
static void Main(string[] args)
{
Thread thread = new Thread(ThreadMethod);
thread.Start();
thread.Interrupt();
Console.Read();
}
private static void ThreadMethod()
{
try
{
Thread.Sleep(Timeout.Infinite);
}
catch (ThreadInterruptedException)
{
Console.Write("ThreadInterruptedException has been called forcibly.");
}
}
上記のプログラムを実行すると、コンソールに「ThreadInterruptedExceptionが強制的に呼び出されました」というメッセージが表示されます。
中断されているスレッドがブロックされていない場合はどうなりますか?ブロックされていないスレッドでThread.Interruptを呼び出すと、スレッドは次にブロックされるまで実行を続けます。ほとんどの場合、Thread.Interruptを使用する必要はまったくありません。シグナリング構造またはキャンセルトークンを使用して同じことを実現できます。
Thread.AbortメソッドまたはThread.Interruptメソッドを使用する必要がありますか?
では、プログラムでThread.AbortメソッドとThread.Interruptメソッドをいつ使用する必要がありますか?特定の操作をキャンセルする必要がある場合、これらの方法のどれを使用する必要がありますか?私の正直な答えは、スレッドを終了するためにこれらのメソッドのいずれかを使用してはならないということです。 Thread.AbortまたはThread.Interruptメソッドを使用してスレッドを終了しないことをお勧めします。同期オブジェクト(WaitHandlesやSemaphoresなど)を利用して、使用しているスレッドを正常に終了する必要があります。次のコードスニペットは、WaitHandleを利用して、スレッドを正常に停止できるようにする方法を示しています。
private void ThreadMethod()
{
while(!manualResetEventObject.WaitOne(TimeSpan.FromMilliseconds(100)))
{
//Write your code here
}
}
スレッドを正常に終了するための代替アプローチとして、揮発性の「ブール」変数を利用することもできます。次に、ユーザーアクティビティのUIスレッドでこの変数を設定し(ユーザーがUIの[キャンセル]ボタンをクリックしてスレッドを終了したと想定)、ワーカーで変数の値を随時確認できます。ユーザーインターフェイスで変数が設定されているかどうかを確認するスレッド(スレッドの終了を示す「false」の値など)。