スレッドの同期
更新 : 2007 年 11 月
スレッド処理されたアプリケーションを作成するときに、スレッドとプログラムの他の部分との同期をとることが必要な場合があります。同期化機能を使うと、マルチスレッド プログラミングの非構造的な性質と、同期的な処理の構造的な順次性を折衷できます。
使用できる同期化技法は次のとおりです。
特定の順序でタスクを実行する必要のあるときには、コードの実行順序を常に明示的に制御する。
または
2 つのスレッドで同時に同じリソースを共有するときに発生する可能性のある問題を回避する。
たとえば、同期を使用すると、別のスレッドで実行中のデータ取得プロシージャが終了するまで、表示プロシージャを待たせることができます。
同期化技法
同期には、ポーリングと同期オブジェクトの使用の 2 とおりの方法があります。同期オブジェクトの詳細については、「高度な同期化技法」を参照してください。
ポーリング
ポーリングは、ループの中から非同期呼び出しのステータスを繰り返しチェックします。ポーリングは各種のスレッド プロパティのステータスを繰り返しチェックするため、リソースの浪費が多く、スレッドの管理には最も非効率な方法です。
たとえば、ポーリング時に IsAlive プロパティを使用すると、スレッドが終了したかどうかを確認できます。動作しているスレッドが必ずしも実行中であるとは限らないため、このプロパティの使用には注意が必要です。
スレッドの ThreadState プロパティを使用すると、スレッドのステータスに関する詳細な情報を取得できます。スレッドは複数の状態を持つことがあるため、ThreadState に格納されている値は System.Threading.ThreadState 列挙型の値の組み合わせの場合があります。したがって、ポーリングのときには、関連するスレッドの状態をすべて入念にチェックする必要があります。たとえば、状態が Running でない場合、スレッドは終了している可能性があります。その一方で、スレッドが中断またはスリープしている可能性もあります。
スレッドの終了の待機
Thread.Join メソッドは、別のタスクを開始する前にスレッドが完了したかどうかを判断するために役立ちます。Join メソッドは、スレッドが終了するまで指定された時間待機します。タイムアウトする前にスレッドが終了した場合、Join メソッドは True を返します。それ以外の場合は False を返します。
スレッドの状態を判断できるように、ポーリングはスレッドの実行順序を制御できる代わりに、マルチスレッドの利点をかなり犠牲にします。ポーリングは非常に非効率であるため、一般にはお勧めできません。Join メソッドを使用してスレッドを制御する方法の方が効率的です。Join を使用すると、スレッドが終了するか、または呼び出しがタイムアウトになるか (タイムアウトが指定されている場合) のいずれかまで、呼び出し元のプロシージャは待機します。"join" という名前は、新しいスレッドの作成が実行パスのフォークにあたるという意味を持ちます。Join を使用すると、個別の実行パスを単一のスレッドに再度マージできます。
図 1 スレッド処理
Join が同期呼び出し、つまりブロックする呼び出しであるという点は明確です。Join メソッドまたは待機ハンドルの待機メソッドを呼び出すと、呼び出し元のプロシージャは停止し、スレッドからの終了通知を待ちます。
Sub JoinThreads()
Dim Thread1 As New System.Threading.Thread(AddressOf SomeTask)
Thread1.Start()
Thread1.Join() ' Wait for the thread to finish.
MsgBox("Thread is done")
End Sub
Sub SomeTask()
' Insert code to perform a task here.
End Sub
この方法はスレッドを簡単に制御でき、少数のスレッドを管理するのには便利ですが、多くのプロジェクトに使用するのは困難です。スレッドの同期をとるために使用できるいくつかの手法については、「高度な同期化技法」を参照してください。