このページをはてなブックマークに追加このページを含むはてなブックマーク このページをlivedoor クリップに追加このページを含むlivedoor クリップ

目次

バックグラウンドワーカーの基本動作

1:メインスレッドからバックグラウンドワーカーのRunWorkerAsyncメソッドを呼ぶ。

2:バックグラウンドワーカーでDoWorkイベントが発生する。このイベント内で時間のかかる処理などを実行する。

3:DoWorkイベントメソッドの実行が終わると、バックグラウンドワーカーでRunWorkerCompletedイベントが発生する。このイベントはメインスレッドで実行される。

メインスレッドバックグラウンドスレッド
DoWorkイベント発生
RunWorkerCompletedイベント発生

バックグラウンドスレッドに情報を渡す

 バックグラウンドスレッドを開始するために、メインスレッドはバックグラウンドワーカーのRunWorkerAsyncメソッドを実行する。その際、引数にObject型のパラメータを指定できる。ここにバックグラウンドスレッドに渡したい情報を指定する。  すると、バックグラウンドスレッド側はDoWorkイベントメソッドの仮引数であるDoWorkEventArgs型のeのArgumentプロパティを参照することで情報を取り出すことができる。

バックグラウンド処理の終了

 バックグラウンドメソッドのDoWorkイベントメソッドが終了すると、メインスレッドでRunWorkerCompletedイベントが発生する。

 RunWorkerCompletedのイベントメソッドは次の2つの仮引数を持つ。

  1. イベントの発生したオブジェクトを示すsender
  2. RunWorkerCompletedEventArgs型のe
    • e.Errorプロパティに例外オブジェクトが設定されていれば、DoWorkイベントメソッドで例外が発生したと判断できる。
    • DoWorkイベントメソッド開始時にメインスレッドからバックグラウンドスレッドにパラメータを渡したように、DoWorkイベントメソッドからメインスレッドにパラメータを渡すことが可能である。
      • e.Rusultプロパティでやり取りされる。

バックグラウンド処理が終了するタイミング

  1. DoWorkイベントメソッドが正常に終了した。
  2. DoWorkイベントメソッドで例外が発生して、スローされてきた。
  3. DoWorkイベントメソッド内でバックグラウンドのキャンセルが実行された。

バックグラウンド処理の注意

  • DoWorkイベントメソッド内では、コントロールなどのインタフェースにアクセスしてはいけない。
    • なぜならば、Windowsのフォームに関するコンポーネントはスレッドセーフ*1ではないからである。
    • バックグラウンドワーカーのWorkerReportsProgressプロパティをTrueに設定すれば、DoWorkイベントメソッド内でReportProgressメソッドを実行して、メインスレッドでProgressChangedイベントを発生させることができる。その際、バックグラウンド処理の進捗や状態を渡すこともできる。
      • つまり、バックグラウンド処理中にコントロールにアクセスしたい場合は、バックグラウンドスレッドから一旦メインスレッドに戻ってからコントロールにアクセスし、またバックグランドスレッドに戻ってくるという手続きになる。
  • 1つのバックグラウンドワーカーで同時に行えるバックグラウンド処理は1つだけである。
    • つまり、バックグラウンドスレッドの実行中に、再度RunWorkerAsyncメソッドを実行してはいけない。
    • すでにバックグラウンドワーカーが実行中かどうかはIsBusyプロパティを参照すれば確認できる。

バックグラウンド処理の停止

メインスレッドからバックグラウンドスレッドの処理を停止する

 メインスレッドでBackgroundWorker.CancelAsyncメソッドを実行する。すると、バックグラウンドワーカーのCancellationPendingプロパティがTrueに変化する。バックグラウンドスレッドでは、CancellationPendingプロパティを定期的に監視しており、このプロパティがTrueになると、停止処理に移行する。

 バックグラウンドワーカーは停止処理として、イベントメソッドのパラメータeのCancelプロパティをTrueに設定して、処理を中断する。

 その後、メインスレッドのRunWorkerCompletedイベントが発生する。つまり、RunWorkerCompletedイベントメソッドのe.Cancelledプロパティを参照することで、バックグラウンドスレッドが正常に終了したのか、こちからの停止命令で中断したのかを判定できる。

メモ

  • ReportProgress()を使うときは、第1引数にInteger、第2引数にProgressChanedイベントに引き渡したい情報を指定する。
    • ProgressChangedイベント側では、e.ProgressPercentageでReportProgress()の第1引数、e.UserStateでReportProgress()の第2引数を取得できる。
  • バッググラウンド処理をキャンセルする場合は、CancelAsync()メソッドを実行する。
    • そのためには、そのBackGourndWorkerのWorkerSupportsCancellationをTrueにしておく必要がある。
      • これを忘れると、「System.InvalidOperationException: この BackgroundWorker はキャンセル操作をサポートしないように指定されています。キャンセル操作をサポートするように指定するには、WorkerSupportsCancellation を変更してください。」という例外が発生する。
    • CancelAsync()メソッドが実行されると、CancellationPendingプロパティがTrueに変化するので、DoWokerイベント内などでその変化を捉えて、e.Cancel = Trueにすればよ。
    • RunWorkerCompletedイベントでは、仮引数eのCancelledプロパティで、キャンセルが発生したことを知ることできる。

参考文献

  • 『VisualBasic2008入門』


*1 複数のスレッドから同時にアクセスしても問題がないという意味。