屏障

System.Threading.Barrier 是同步基元,可以使多个线程(称为“参与者”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 对象与任何类型的隐式联接,其中包括:

有关详细信息,请参阅使用延续任务链接任务

另请参阅