Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Un System.Threading.Barrier è una primitiva di sincronizzazione che consente a più thread (noti come partecipanti) di funzionare simultaneamente su un algoritmo in fasi. Ogni partecipante esegue fino a raggiungere il punto di barriera nel codice. La barriera rappresenta la fine di una fase di lavoro. Quando un partecipante raggiunge la barriera, si blocca fino a quando tutti i partecipanti non hanno raggiunto la stessa barriera. Dopo che tutti i partecipanti hanno raggiunto la barriera, è possibile richiamare facoltativamente un'azione post-fase. Questa azione post-fase può essere usata per eseguire azioni da un singolo thread, mentre tutti gli altri thread sono ancora bloccati. Dopo l'esecuzione dell'azione, i partecipanti vengono tutti sbloccati.
Il frammento di codice seguente illustra 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.
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
Per un esempio completo, vedere Procedura: sincronizzare le operazioni simultanee con una barriera.
Aggiunta e rimozione di partecipanti
Quando si crea un'istanza Barrier , specificare il numero di partecipanti. È anche possibile aggiungere o rimuovere partecipanti in modo dinamico in qualsiasi momento. Ad esempio, se un partecipante risolve la parte del problema, è possibile archiviare il risultato, arrestare l'esecuzione su tale thread e chiamare Barrier.RemoveParticipant per decrementare il numero di partecipanti nella barriera. Quando si aggiunge un partecipante chiamando Barrier.AddParticipant, il valore restituito specifica il numero di fase corrente, che può essere utile per inizializzare il lavoro del nuovo partecipante.
Barriere interrotte
I deadlock possono verificarsi se un partecipante non riesce a raggiungere la barriera. Per evitare questi deadlock, usare gli overload del Barrier.SignalAndWait metodo per specificare un periodo di timeout e un token di annullamento. Questi overload restituiscono un valore booleano che ogni partecipante può controllare prima di continuare con la fase successiva.
Eccezioni post-fase
Se il delegato alla fase posteriore genera un'eccezione, questa viene incapsulata in un oggetto BarrierPostPhaseException, che viene quindi propagato a tutti i partecipanti.
Barriera rispetto a ContinueWhenAll
Le barriere sono particolarmente utili quando i thread eseguono più fasi in cicli. Se il codice richiede solo una o due fasi di lavoro, valutare se usare System.Threading.Tasks.Task oggetti con qualsiasi tipo di join implicito, tra cui:
Per altre informazioni, vedere concatenamento delle attività tramite attività di continuazione.