A System.Threading.Barrier 是一种同步基元,使多个线程(称为 参与者)可以分阶段在算法上并发工作。 每个参与者执行,直到它到达代码中的屏障点。 屏障表示工作一个阶段的结束。 单个参与者到达屏障后将被阻止,直至所有参与者都已达到同一障碍。 所有参与者都已达到屏障后,你可以选择调用阶段后操作。 此阶段结束后的操作可用于由单个线程执行操作,而其他所有线程仍被阻止。 执行此操作后,所有参与者将不受阻止。
以下代码片段显示了基本屏障模式。
// 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添加参与者时,返回值指定当前阶段编号,这对于初始化新参与者的工作可能很有用。
屏障断开
如果一个参与者无法到达屏障,则可能发生死锁。 若要避免这些死锁,请使用 Barrier.SignalAndWait 方法的重载来指定超时期限和取消标记。 这些重载返回一个布尔值,每个参与者都可以在继续下一阶段之前检查该值。
阶段后异常
如果阶段后委托引发异常,则它将包装在 BarrierPostPhaseException 对象中,然后传播到所有参与者。
屏障与 ContinueWhenAll
当线程在循环中执行多个阶段时,屏障特别有用。 如果你的代码只需要一个或两个工作阶段,请考虑是否使用包括隐式联接在内的System.Threading.Tasks.Task对象。
有关详细信息,请参阅使用延续任务链接任务。
另请参阅
- 线程对象和功能
- 如何同步并发操作与屏障