Dela via


Barriär

A System.Threading.Barrier är en synkroniseringsprimering som gör att flera trådar (kallas deltagare) kan arbeta samtidigt med en algoritm i faser. Varje deltagare körs tills den når barriärpunkten i koden. Barriären representerar slutet på en arbetsfas. När en deltagare når barriären blockeras den tills alla deltagare har nått samma barriär. När alla deltagare har nått barriären kan du anropa en åtgärd efter fasen. Den här åtgärden efter fasen kan användas för att utföra åtgärder av en enda tråd medan alla andra trådar fortfarande blockeras. När åtgärden har utförts avblockeras alla deltagare.

Följande kodfragment visar ett grundläggande barriärmönster.


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

Ett fullständigt exempel finns i Så här synkroniserar du samtidiga åtgärder med en barriär.

Lägga till och ta bort deltagare

När du skapar en Barrier instans anger du antalet deltagare. Du kan också lägga till eller ta bort deltagare dynamiskt när som helst. Om en deltagare till exempel löser sin del av problemet kan du lagra resultatet, stoppa körningen av tråden och anropa Barrier.RemoveParticipant för att minska antalet deltagare i barriären. När du lägger till en deltagare genom att anropa Barrier.AddParticipantanger returvärdet det aktuella fasnumret, vilket kan vara användbart för att initiera den nya deltagarens arbete.

Brutna barriärer

Dödlägen kan inträffa om en deltagare inte når barriären. Undvik dessa dödlägen genom att använda överlagringarna för Barrier.SignalAndWait metoden för att ange en tidsgräns och en annulleringstoken. Dessa överlagringar returnerar ett booleskt värde som varje deltagare kan kontrollera innan det fortsätter till nästa fas.

Undantag efter fas

Om ombudet efter fasen utlöser ett undantag omsluts det i ett BarrierPostPhaseException objekt som sedan sprids till alla deltagare.

Barriär jämfört med ContinueWhenAll

Hinder är särskilt användbara när trådarna utför flera faser i loopar. Om koden bara kräver en eller två faser av arbetet bör du överväga om du vill använda System.Threading.Tasks.Task objekt med någon form av implicit koppling, inklusive:

Mer information finns i Länka uppgifter med hjälp av fortsättningsuppgifter.

Se även