【C#】スレッドの処理の途中で外部からキャンセル終了する

C#

スレッドの処理を外部から途中で終了させる方法を紹介します。

方法1:フラグを使用

フラグを使用してスレッドのループを制御し、外部からそのフラグを変更することでスレッドの実行を終了させる方法です。

using System;
using System.Threading;

class Program
{
    private static bool IsCanceled = false; // スレッドの実行をキャンセルするフラグ

    static void Main(string[] args)
    {
        Thread workerThread = new Thread(WorkerMethod);
        workerThread.Start();

        Console.WriteLine("Press any key to stop the thread...");
        Console.ReadKey();

        IsCanceled = true;   // スレッドに停止を指示
        workerThread.Join(); // スレッドの終了を待機

        Console.WriteLine("Thread has been stopped.");
    }

    static void WorkerMethod()
    {
        while (!IsCanceled) // キャンセルされるまで実行
        {
            try
            {
                Console.WriteLine("Working...");
                Thread.Sleep(1000); // 仕事のシミュレーション
            }
            catch (Exception ex)
            {
                Console.WriteLine("エラーが発生しました: " + ex.Message);
                return; // エラーが発生した場合はスレッドを終了
            }
        }
    }
}

    方法2:Thread.Interrupt メソッドを使用

    Thread.Interrupt メソッドを使用することでスレッド内で例外を発生させて途中終了する方法です。

    using System;
    using System.Threading;
    
    class Program
    {
        static void Main(string[] args)
        {
            Thread workerThread = new Thread(WorkerMethod);
            workerThread.Start();
    
            Console.WriteLine("Press any key to interrupt the thread...");
            Console.ReadKey();
    
            workerThread.Interrupt(); // スレッドの中断を試みる
            workerThread.Join(); // スレッドの終了を待機
    
            Console.WriteLine("Thread has been interrupted and stopped.");
        }
    
        static void WorkerMethod()
        {
            try
            {
                while (true)
                {
                    Console.WriteLine("Working...");
                    Thread.Sleep(1000); // 仕事のシミュレーション。この状態でInterruptが呼び出されるとThreadInterruptedExceptionが発生
                }
            }
            catch (ThreadInterruptedException ex)
            {
                Console.WriteLine("スレッドが中断されました: " + ex.Message);
                // 必要に応じてクリーンアップ処理をここに記述
            }
        }
    }
    

    解説

    • スレッドの中断: ユーザーの入力を受け取った後、workerThread.Interrupt(); によってスレッドを中断しようとします。この時、スレッドが Thread.Sleep などで待機中であれば、ThreadInterruptedException が発生します。
    • 例外の処理: WorkerMethod 内で ThreadInterruptedException をキャッチし、スレッドの中断を検知します。ここで適切なクリーンアップ処理を行うことが可能です。

    Thread.Interrupt を使用することで、スレッドがブロック状態(※)にある際にそれを安全に中断し、終了処理を行う機会を得ることができます。ただし、この方法はスレッドが特定のブロック状態にある場合にのみ有効であり、実行中の処理を任意の位置で中断するわけではないため、使用する際にはその挙動を正しく理解しておく必要があります。

    ※ブロック状態の例は以下の通りです。
    Thread.Sleep: スレッドが指定された時間だけ休止している状態。
    Thread.Join: スレッドが他のスレッドの終了を待っている状態。
    Monitor.Wait: スレッドがオブジェクトのロックの解放を待っている状態。

    以下のように、無限ループを実行しているスレッドは、特定のブロック状態(SleepやJoinなど)にないため、Thread.Interrupt を使用しても ThreadInterruptedException を発生させることはできません。

    while(true) 
    {
        Counter++;
    }
    タイトルとURLをコピーしました