Sdílet prostřednictvím


Bariéra

A System.Threading.Barrier je primitivní synchronizace, která umožňuje souběžné práci s algoritmem ve fázích více vláken (označovaných jako účastníci). Každý účastník se spustí, dokud nedosáhne bodu bariéry v kódu. Bariéra představuje konec jedné fáze práce. Když účastník dosáhne bariéry, blokuje, dokud všichni účastníci nedosáhli stejné bariéry. Jakmile všichni účastníci dosáhnou bariéry, můžete volitelně vyvolat akci po fázi. Tuto akci po fázi lze použít k provádění akcí jedním vláknem, zatímco všechna ostatní vlákna jsou stále blokovaná. Po provedení akce se všichni účastníci odblokují.

Následující fragment kódu ukazuje základní vzor bariéry.


// 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

Úplný příklad najdete v tématu Postupy: Synchronizace souběžných operací s bariérou.

Přidávání a odebírání účastníků

Při vytváření Barrier instance zadejte počet účastníků. Účastníky můžete přidávat nebo odebírat také dynamicky. Pokud například jeden účastník vyřeší jeho část problému, můžete uložit výsledek, zastavit provádění na tomto vlákně a volat Barrier.RemoveParticipant dekrementace počtu účastníků v bariérě. Když přidáte účastníka voláním Barrier.AddParticipant, návratová hodnota určuje aktuální číslo fáze, které může být užitečné pro inicializaci práce nového účastníka.

Poškozené bariéry

Zablokování může nastat, pokud jeden účastník nedorazí do bariéry. Pokud se chcete těmto zablokováním vyhnout, použijte přetížení Barrier.SignalAndWait metody k určení časového limitu a tokenu zrušení. Tato přetížení vrací logickou hodnotu, kterou může každý účastník zkontrolovat, než bude pokračovat k další fázi.

Výjimky po fázi

Pokud postfázový delegát vyvolá výjimku, je zabalen do objektu BarrierPostPhaseException , který se pak rozšíří do všech účastníků.

Bariéra versus ContinueWhenAll

Bariéry jsou zvlášť užitečné, když vlákna provádějí více fází ve smyčce. Pokud váš kód vyžaduje pouze jednu nebo dvě fáze práce, zvažte, jestli použít System.Threading.Tasks.Task objekty s jakýmkoli druhem implicitního spojení, včetně:

Další informace naleznete v tématu Zřetězování úkolů pomocí úloh pokračování.

Viz také