屏障

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 物件搭配任何一種隱含聯結,包括:

如需詳細資訊,請參閱使用接續工作鏈結工作

另請參閱