|
分類:[VB.NET/VB2005 以降]
開発環境:Visual Studio 2017 Community
同一の処理を行うBackgroundWorkerを複数使った並列処理を実現したいと思い、以下のようなコード(要点のみ)で実装を行いましたが、
並列処理の停止がうまくできず困っています。
ButtonStartを押すと指定した並列数で処理を開始し、ButtonStopを押すと途中でその処理をキャンセルするものです。
Dim bg() As System.ComponentModel.BackgroundWorker '並列処理を行うためのBackgroundWorkerのインスタンス
Private Sub ButtonStart_Click(sender As Object, e As EventArgs) Handles ButtonStart.Click
Dim numThread As Integer '並列処理の同時実行数
Dim bgParameter As Parameter 'BackgroundWorkerに渡す引数
'既にBackgroundWorkerが動いていた場合は何もしない
If(bg IsNot Nothing) Then
For i As Integer = 0 To bg.GetUpperbound(0)
If(bg(i).IsBusy = True) Then
Exit Sub
End If
Next
End If
numThread = 値を決定する処理
'指定した数だけBackgroundWorkerのインスタンスを生成
ReDim bg(numThread - 1)
For i As Integer = 0 To numThread - 1
'bgで実行する処理の規定
bg(i) = New System.ComponentModel.BackgroundWorker
AddHandler bg(i).DoWork, AddressOf BackgroundWorker1_DoWork
AddHandler bg(i).RunWorkerCompleted, AddressOf BackgroundWorker1_RunWorkerCompleted
'bg(i)を中止可能にする
bg(i).WorkerSupportsCancellation = True
'パラメータをセットしてBackgroundWorkerを起動
bgParameter = 値を決定する処理
bg(i).RunWorkerAsync(bgParameter)
Next
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For i as Integer = 0 To 繰り返しのループ数
If(BackgroundWorker1.CancellationPending = True) Then
e.Cancel = True
Exit For
End If
何か重いループ処理
Next
End Sub
Private Sub ButtonStop_Click(sender As Object, e As EventArgs) Handles ButtonStop.Click
If (bg IsNot Nothing) Then
For i As Integer = 0 To bg.GetUpperBound(0)
If (bg(i).IsBusy = True) Then
bg(i).CancelAsync()
End If
Next
End If
End Sub
実際にプログラムを走らせてみると並列処理そのものはうまく動作するのですが、ButtonStopをクリックしてもBackgroundWorkerが停止せず最後まで進んでしまいます。
BackgroundWorkerをキャンセル可能にする際の注意点としては
・WorkerSupportsCancellationをTrueにする
・DoWorkの中で定期的にCancellationPendingプロパティをチェックし、それがTrueになっていたらDoWorkを終了させるようにコードを書く
・終了させたい場合はCancelAsyncを使う
のように理解しており、一応その注意点は守っているつもりなのですが・・・。
今回のようなBackgroundWorkerを複数使う並列処理の場合はまた何か注意すべき点があるのでしょうか?
本来であれば今は古いBackgroundWorkerではなくAsync/Await等の新しい手法を使うべきなのだとは思いますが、基本的な使い方が理解できていないのでBackgroundWorkerで何とかしたいと思っています。
ご教示いただければ幸いです。
|