スレッドの処理を途中で停止、キャンセルする

BackgroundWorkerを使って実行中の別スレッドの処理をキャンセルする方法です。
(前節のサンプルにスレッドを停止する2つ目のボタンを追加しています)

まず準備として
BackgroundWorkerのWorkerSupportsCancellationプロパティーにtrueを設定し
このスレッドがキャンセルに対応することを設定します。

実際のキャンセル処理ですが
BackgroundWorkerのCancelAsync関数を任意のタイミングで呼び出します。

後は、DoWorkハンドラ内で定期的にキャンセルされていないか
CancellationPendingプロパティーを監視し、

CancellationPendingにtrueが設定されていれば
DoWorkEventArgs引数のCancelプロパティーにtrueを設定して
処理を中断(return)します。

処理が完了しても中断しても
最後はRunWorkerCompletedハンドラが呼ばれるので
そこでキャンセルによる停止なのか処理が完了したのか
理由を参照します。(e.Cancelled)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // RunWorkerAsyncが呼び出された時に発生
            backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);

            // BackgroundWorkerでの処理が完了した時に発生
            backgroundWorker1.RunWorkerCompleted += 
            	new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);

            // キャンセルされることを許可
            backgroundWorker1.WorkerSupportsCancellation = true;
        }

        void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if(e.Cancelled)
                MessageBox.Show("処理はキャンセルされました");
            else
                MessageBox.Show("処理完了");
        }

        void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 0; i < 1000; i++)
            {
                // キャンセルされた?
                if (backgroundWorker1.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                System.Diagnostics.Debug.Write("@");
                Application.DoEvents();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // BackgroundWorkerが処理中でなければ
            if (!backgroundWorker1.IsBusy)
            {
                // バックグラウンド処理を開始
                backgroundWorker1.RunWorkerAsync();

                for (int i = 0; i < 1000; i++)
                {
                    System.Diagnostics.Debug.Write("_");
                    Application.DoEvents();
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            // 処理をキャンセルします
            backgroundWorker1.CancelAsync();
        }
    }
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)