Condividi tramite


Barriera (.NET Framework)

Una barriera è una primitiva di sincronizzazione definita dall'utente che consente di utilizzare contemporaneamente più thread (definiti partecipanti) in un algoritmo in fasi. Ogni partecipante viene eseguito fino a che non raggiunge il punto di barriera nel codice. La barriera rappresenta la fine di una fase di lavoro. Quando un partecipante raggiunge la barriera, viene bloccato fino a che tutti i partecipanti non hanno raggiunto la stessa barriera. Una volta che i partecipanti hanno raggiunto la barriera, è possibile richiamare facoltativamente un'azione post-fase. Quest'azione può essere utilizzata per eseguire azioni da un singolo thread mentre tutti gli altri thread sono ancora bloccati. Una volta eseguita l'azione, tutti i partecipanti vengono sbloccati.

Nel frammento di codice seguente viene illustrato un modello di barriera di base.


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

 // 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 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();

 }

Per un esempio completo, vedere Procedura: sincronizzare operazioni simultanee con una barriera.

Aggiunta e rimozione di partecipanti

Quando si crea un oggetto Barrier, occorre specificare il numero di partecipanti. È inoltre possibile aggiungere o rimuovere partecipanti in modo dinamico in qualsiasi momento. Se, ad esempio, un partecipante risolve la sua parte di problema, è possibile archiviare il risultato, arrestare l'esecuzione nel thread e chiamare RemoveParticipant per diminuire il numero di partecipanti nella barriera. Quando si aggiunge un partecipante chiamando AddParticipant, il valore restituito specifica il numero di fase corrente, che può essere utile per inizializzare il lavoro del nuovo partecipante.

Barriere interrotte

Se un partecipante non riesce a raggiungere la barriera, possono verificarsi deadlock. Per evitare questi deadlock, utilizzare gli overload del metodo SignalAndWait per specificare un periodo di timeout e un token di annullamento. Questi overload restituiscono un valore booleano che ogni partecipante può controllare prima di passare alla fase successiva.

Eccezioni post-fase

Se il delegato post-fase genera un'eccezione, ne viene eseguito il wrapping in un oggetto BarrierPostPhaseException, che viene quindi propagato a tutti i partecipanti.

Barrier e ContinueWhenAll

Le barriere risultano particolarmente utili quando i thread eseguono più fasi nei cicli. Se il codice richiede solo una o due fasi di lavoro, prendere in considerazione l'utilizzo di oggetti System.Threading.Tasks.Task con qualsiasi tipo di join implicito, inclusi i seguenti:

Per ulteriori informazioni, vedere Procedura: concatenare più attività con continuazioni.

Vedere anche

Attività

Procedura: sincronizzare operazioni simultanee con una barriera

Altre risorse

Oggetti e funzionalità del threading