System.Threading.Barrierは同期プリミティブであり、複数のスレッド (参加者と呼ばれます) がアルゴリズムで同時に段階的に動作できるようにします。 各参加者は、コード内のバリア ポイントに到達するまで実行されます。 バリアは、1 フェーズの作業の終了を表します。 参加者がバリアに到達すると、すべての参加者が同じバリアに到達するまでブロックされます。 すべての参加者がバリアに到達したら、必要に応じてフェーズ後アクションを呼び出すことができます。 このフェーズ後のアクションは、他のすべてのスレッドがまだブロックされている間に、1 つのスレッドによってアクションを実行するために使用できます。 アクションが実行されると、参加者はすべてブロック解除されます。
次のコード スニペットは、基本的なバリア パターンを示しています。
// Create the Barrier object, and supply a post-phase delegate
// to be invoked at the end of each phase.
Barrier barrier = new Barrier(2, (bar) =>
{
// Examine results from all threads, determine
// whether to continue, create inputs for next phase, etc.
if (someCondition)
success = true;
});
// Define the work that each thread will perform. (Threads do not
// have to all execute the same method.)
void CrunchNumbers(int partitionNum)
{
// Up to System.Int64.MaxValue phases are supported. We assume
// in this code that the problem will be solved before that.
while (success == false)
{
// Begin phase:
// Process data here on each thread, and optionally
// store results, for example:
results[partitionNum] = ProcessData(data[partitionNum]);
// End phase:
// After all threads arrive,post-phase delegate
// is invoked, then threads are unblocked. Overloads
// accept a timeout value and/or CancellationToken.
barrier.SignalAndWait();
}
}
// Perform n tasks to run in parallel. For simplicity
// all threads execute the same method in this example.
static void Main()
{
var app = new BarrierDemo();
Thread t1 = new Thread(() => app.CrunchNumbers(0));
Thread t2 = new Thread(() => app.CrunchNumbers(1));
t1.Start();
t2.Start();
}
' Create the Barrier object, and supply a post-phase delegate
' to be invoked at the end of each phase.
Dim barrier = New Barrier(2, Sub(bar)
' Examine results from all threads, determine
' whether to continue, create inputs for next phase, etc.
If (someCondition) Then
success = True
End If
End Sub)
' Define the work that each thread will perform. (Threads do not
' have to all execute the same method.)
Sub CrunchNumbers(ByVal partitionNum As Integer)
' Up to System.Int64.MaxValue phases are supported. We assume
' in this code that the problem will be solved before that.
While (success = False)
' Begin phase:
' Process data here on each thread, and optionally
' store results, for example:
results(partitionNum) = ProcessData(myData(partitionNum))
' End phase:
' After all threads arrive,post-phase delegate
' is invoked, then threads are unblocked. Overloads
' accept a timeout value and/or CancellationToken.
barrier.SignalAndWait()
End While
End Sub
' Perform n tasks to run in parallel. For simplicity
' all threads execute the same method in this example.
Shared Sub Main()
Dim app = New BarrierDemo()
Dim t1 = New Thread(Sub() app.CrunchNumbers(0))
Dim t2 = New Thread(Sub() app.CrunchNumbers(1))
t1.Start()
t2.Start()
End Sub
完全な例については、「 方法: 同時実行操作をバリアと同期する」を参照してください。
参加者の追加と削除
Barrier インスタンスを作成するときに、参加者の数を指定します。 参加者はいつでも動的に追加または削除できます。 たとえば、ある参加者が問題の一部を解決した場合、結果を格納し、そのスレッドでの実行を停止し、 Barrier.RemoveParticipant を呼び出してバリア内の参加者の数を減らすことができます。 Barrier.AddParticipantを呼び出して参加者を追加する場合、戻り値は現在のフェーズ番号を指定します。これは、新しい参加者の作業を初期化するために役立つ場合があります。
破損したバリア
1 人の参加者がバリアに到達できなかった場合、デッドロックが発生する可能性があります。 これらのデッドロックを回避するには、 Barrier.SignalAndWait メソッドのオーバーロードを使用して、タイムアウト期間とキャンセル トークンを指定します。 これらのオーバーロードは、すべての参加者が次のフェーズに進む前に確認できるブール値を返します。
フェーズ後の例外
フェーズ後のデリゲートが例外をスローすると、 BarrierPostPhaseException オブジェクトにラップされ、すべての参加者に伝達されます。
バリアと ContinueWhenAll
バリアは、スレッドがループ内で複数のフェーズを実行している場合に特に便利です。 コードで 1 つまたは 2 つの作業フェーズのみが必要な場合は、次のような任意の種類の暗黙的な結合で System.Threading.Tasks.Task オブジェクトを使用するかどうかを検討します。
詳細については、「継続タスクを使用したタスクの連結」を参照してください。
こちらも参照ください
.NET