Compartir a través de


Barrier (.NET Framework)

Una barrera es un primitiva de sincronización definida por el usuario que permite que varios subprocesos (denominados participantes) trabajar simultáneamente en un algoritmo en fases. Cada participante se ejecuta hasta que alcanza el punto de la barrera en el código. La barrera representa el fin de una fase de trabajo. Cuando un participante alcanza la barrera, se bloquea hasta que todos los participantes hayan alcanzado la misma barrera. Después de que todos los participantes han alcanzado la barrera, se puede invocar, si se desea, una acción de fase posterior. Esta acción de fase posterior se puede utilizar para que un solo subproceso realice acciones mientras los demás permanecen bloqueados. Una vez ejecutada la acción, se desbloquean todos los participantes.

El siguiente fragmento de código muestra un modelo de barrera básico.


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

 }

Para obtener un ejemplo completo, vea Cómo: Sincronizar operaciones simultáneas con una clase Barrier.

Agregar y quitar participantes

Al crear Barrier, especifique el número de participantes. También puede agregar o quitar participantes dinámicamente en cualquier momento. Por ejemplo, si un participante resuelve su parte del problema, puede almacenar el resultado, detener la ejecución de ese subproceso y llamar a RemoveParticipant para disminuir el número de participantes de la barrera. Al agregar un participante llamando a AddParticipant, el valor devuelto especifica el número de la fase actual, lo que puede resultar útil para inicializar el trabajo del nuevo participante.

Barreras rotas

Se pueden producir interbloqueos si un participante no consigue alcanzar la barrera. Para evitar estos interbloqueos, utilice las sobrecargas del método SignalAndWait a fin de especificar un tiempo de espera y un token de cancelación. Estas sobrecargas devuelven un valor Boolean que cada participante puede comprobar antes de continuar a la fase siguiente.

Excepciones de fase posterior

Si el delegado de la fase posterior produce una excepción, se encapsula en un objeto BarrierPostPhaseException que se propaga a continuación a todos los participantes.

Diferencias entre las barreras y ContinueWhenAll

Las barreras resultan especialmente útiles cuando los subprocesos realizan varias fases en bucles. Si el código requiere solamente una o dos fases de trabajo, puede ser mejor utilizar objetos System.Threading.Tasks.Task con cualquier tipo de unión implícita, como las siguientes:

Para obtener más información, vea Cómo: Encadenar varias tareas con continuaciones.

Vea también

Tareas

Cómo: Sincronizar operaciones simultáneas con una clase Barrier

Otros recursos

Objetos y características de subprocesos