VBでマルチスレッド(BackgroundWorker)

メモ:  Category:vb

VB2005では、BackgroundWorkerコントロールを使うことで簡単にマルチスレッドプログラミングを作成することができます。

ツールボックス

このBackgroundWorkerには、いくつかのイベントが用意されています。

DoWork
スレッドの開始時に呼ばれます。(RunWorkerAsyncが呼び出されたときに発生します。)
ProgressChanged
ReportProgressが呼び出されたときに発生します。進捗具合などをここで表示します。
RunWorkerCompleted
バックグラウンド操作の完了時、キャンセル時、またはバックグラウンド操作によって例外が発生したときに発生します。
Disposed

BackgroundWorkerの例

BackgroundWorkerは、時間のかかる処理を裏(別のスレッド)で処理をさせ、親フォームに進捗を表示するといった作業を容易に実現できます。

Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
           Handles btnStart.Click

    ' スレッドの開始
    backgroundworker.RunWorkerAsync()
End Sub

Private Sub backgroundworker_DoWork(ByVal sender As Object, _
             ByVal e As System.ComponentModel.DoWorkEventArgs) Handles backgroundworker.DoWork

    ' BackgroundWorkerの取得(スレッドを作成したオブジェクト)
    Dim objWorker As System.ComponentModel.BackgroundWorker = _
                CType(sender, System.ComponentModel.BackgroundWorker)
    
    ' 時間のかかる裏で動かしたい処理
    e.Result = CountThread(objWorker, e)

End Sub

Private Function CountThread(ByVal worker As System.ComponentModel.BackgroundWorker, _
    ByVal e As System.ComponentModel.DoWorkEventArgs) As Long

    Dim result As Long = 0
    Dim intProgress As Integer

    ' 印刷処理だと思って
    For i As Integer = 1 To 60000
        ' スレッドキャンセルの確認
        If worker.CancellationPending Then
            e.Cancel = True
            Exit For
        Else
           ・・・
            intProgress = CType(CSng(i) / CSng(60000) * 100, Integer)

            ' ProgressChangedイベントを発生させる
            worker.ReportProgress(intProgress)
        End If
    Next

    Return result
End Function

' 進捗状況更新イベント
Private Sub backgroundworker_ProgressChanged(ByVal sender As Object, _
              ByVal e As System.ComponentModel.ProgressChangedEventArgs) _
              Handles backgroundworker.ProgressChanged

    ' パーセンテージの場合 e.ProgressPercentage で取得可能
    prgStatus.Value = e.ProgressPercentage
    prgStatus.Update()
End Sub

' スレッド処理終了
Private Sub backgroundworker_RunWorkerCompleted(ByVal sender As Object, _
             ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
             Handles backgroundworker.RunWorkerCompleted

    ' 最初に、例外がスローされた場合の処理
    If Not (e.Error Is Nothing) Then
        MessageBox.Show(e.Error.Message)
    ElseIf e.Cancelled Then
        ' 次に、ユーザーが計算をキャンセルした場合の処理
        ・・・
    Else
        ' 正常に完了した場合の処理
        ・・・
    End If
End Sub

別スレッドを開始するトリガーとなるのが、BackgroundWorkerのRunWorkerAsync()関数になります。

RunWorkerAsyncによりDoWorkイベントが発生します。

スレッド側に引数を渡したい場合、RunWorkerAsync関数で渡すことができます。RunWorkerAsyncで渡した引数は、DoWorkのDoWorkEventArgs.Argumentで受取ることができます。進捗具合を送信するには、スレッド内でReportProgress関数を呼びます。この関数によりProgressChangedイベントが発生します。

ReportProgressを使用する場合、BackgroundWorkerコントロールのWorkerReportsProgressプロパティをTrueにしておく必要があります。

スレッドが終了するとRunWorkerCompletedイベントが発生します。ここで別スレッドの結果を得ることができます。

bluenote by BBB