Delen via


Barrière

A System.Threading.Barrier is een synchronisatieprimitief waarmee meerdere threads (ook wel deelnemers genoemd) gelijktijdig kunnen werken aan een algoritme in fasen. Elke deelnemer wordt uitgevoerd totdat deze het barrièrepunt in de code bereikt. De barrière vertegenwoordigt het einde van één fase van het werk. Wanneer een deelnemer de barrière bereikt, wordt deze geblokkeerd totdat alle deelnemers dezelfde barrière hebben bereikt. Nadat alle deelnemers de barrière hebben bereikt, kunt u eventueel een actie na de fase aanroepen. Deze actie na de fase kan worden gebruikt om acties uit te voeren door één thread, terwijl alle andere threads nog steeds worden geblokkeerd. Nadat de actie is uitgevoerd, worden de deelnemers allemaal gedeblokkeerd.

In het volgende codefragment ziet u een basisbarrièrepatroon.


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

Zie Procedure voor een volledig voorbeeld : gelijktijdige bewerkingen synchroniseren met een barrière.

Deelnemers toevoegen en verwijderen

Wanneer u een Barrier exemplaar maakt, geeft u het aantal deelnemers op. U kunt deelnemers ook op elk gewenst moment dynamisch toevoegen of verwijderen. Als één deelnemer bijvoorbeeld het deel van het probleem oplost, kunt u het resultaat opslaan, de uitvoering van die thread stoppen en het Barrier.RemoveParticipant aantal deelnemers in de barrière verlagen. Wanneer u een deelnemer toevoegt door te bellen Barrier.AddParticipant, geeft de retourwaarde het huidige fasenummer op, wat handig kan zijn om het werk van de nieuwe deelnemer te initialiseren.

Gebroken barrières

Impasses kunnen optreden als één deelnemer de barrière niet kan bereiken. Als u deze impasses wilt voorkomen, gebruikt u de overbelasting van de Barrier.SignalAndWait methode om een time-outperiode en een annuleringstoken op te geven. Deze overbelastingen retourneren een Booleaanse waarde die elke deelnemer kan controleren voordat deze verdergaat met de volgende fase.

Uitzonderingen na de fase

Als de gedelegeerde na de fase een uitzondering genereert, wordt deze verpakt in een BarrierPostPhaseException object dat vervolgens wordt doorgegeven aan alle deelnemers.

Barrière versus ContinueWhenAll

Barrières zijn vooral handig wanneer de threads meerdere fasen in lussen uitvoeren. Als uw code slechts één of twee fasen van werk vereist, kunt u overwegen of u objecten wilt gebruiken System.Threading.Tasks.Task met elk soort impliciete join, waaronder:

Zie Koppelingstaken met behulp van vervolgtaken voor meer informatie.

Zie ook