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

En el ejemplo siguiente se muestra cómo sincronizar tareas simultáneas con Barrier.

Ejemplo

El propósito del programa siguiente es contar cuántas iteraciones o fases son necesarias para que dos subprocesos busquen cada uno su mitad de la solución en la misma fase utilizando un algoritmo aleatorio para reorganizar las palabras. Después de que cada subproceso haya ordenado sus palabras, la operación de barrera posterior a la fase compara los dos resultados para ver si la oración completa se ha representado en el orden de palabras correcto.

//#define TRACE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BarrierSimple
{
    class Program
    {
        static string[] words1 = new string[] { "brown",  "jumps", "the", "fox", "quick"};
        static string[] words2 = new string[] { "dog", "lazy","the","over"};
        static string solution = "the quick brown fox jumps over the lazy dog.";

        static bool success = false;
        static Barrier barrier = new Barrier(2, (b) =>
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < words1.Length; i++)
            {
                sb.Append(words1[i]);
                sb.Append(" ");
            }
            for (int i = 0; i < words2.Length; i++)
            {
                sb.Append(words2[i]);

                if(i < words2.Length - 1)
                    sb.Append(" ");
            }
            sb.Append(".");
#if TRACE
            System.Diagnostics.Trace.WriteLine(sb.ToString());
#endif
            Console.CursorLeft = 0;
            Console.Write("Current phase: {0}", barrier.CurrentPhaseNumber);
            if (String.CompareOrdinal(solution, sb.ToString()) == 0)
            {
                success = true;
                Console.WriteLine("\r\nThe solution was found in {0} attempts", barrier.CurrentPhaseNumber);
            }
        });

        static void Main(string[] args)
        {

            Thread t1 = new Thread(() => Solve(words1));
            Thread t2 = new Thread(() => Solve(words2));
            t1.Start();
            t2.Start();

            // Keep the console window open.
            Console.ReadLine();
        }

        // Use Knuth-Fisher-Yates shuffle to randomly reorder each array.
        // For simplicity, we require that both wordArrays be solved in the same phase.
        // Success of right or left side only is not stored and does not count.
        static void Solve(string[] wordArray)
        {
            while(success == false)
            {
                Random random = new Random();
                for (int i = wordArray.Length - 1; i > 0; i--)
                {
                    int swapIndex = random.Next(i + 1);
                    string temp = wordArray[i];
                    wordArray[i] = wordArray[swapIndex];
                    wordArray[swapIndex] = temp;
                }

                // We need to stop here to examine results
                // of all thread activity. This is done in the post-phase
                // delegate that is defined in the Barrier constructor.
                barrier.SignalAndWait();
            }
        }
    }
}
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks


Class Program
    Shared words1() = New String() {"brown", "jumps", "the", "fox", "quick"}
    Shared words2() = New String() {"dog", "lazy", "the", "over"}
    Shared solution = "the quick brown fox jumps over the lazy dog."

    Shared success = False
    Shared barrier = New Barrier(2, Sub(b)
                                        Dim sb = New StringBuilder()
                                        For i As Integer = 0 To words1.Length - 1
                                            sb.Append(words1(i))
                                            sb.Append(" ")
                                        Next
                                        For i As Integer = 0 To words2.Length - 1

                                            sb.Append(words2(i))

                                            If (i < words2.Length - 1) Then
                                                sb.Append(" ")
                                            End If
                                        Next
                                        sb.Append(".")
                                        System.Diagnostics.Trace.WriteLine(sb.ToString())

                                        Console.CursorLeft = 0
                                        Console.Write("Current phase: {0}", barrier.CurrentPhaseNumber)
                                        If (String.CompareOrdinal(solution, sb.ToString()) = 0) Then
                                            success = True
                                            Console.WriteLine()
                                            Console.WriteLine("The solution was found in {0} attempts", barrier.CurrentPhaseNumber)
                                        End If
                                    End Sub)

    Shared Sub Main()
        Dim t1 = New Thread(Sub() Solve(words1))
        Dim t2 = New Thread(Sub() Solve(words2))
        t1.Start()
        t2.Start()

        ' Keep the console window open.
        Console.ReadLine()
    End Sub

    ' Use Knuth-Fisher-Yates shuffle to randomly reorder each array.
    ' For simplicity, we require that both wordArrays be solved in the same phase.
    ' Success of right or left side only is not stored and does not count.       
    Shared Sub Solve(ByVal wordArray As String())
        While success = False
            Dim rand = New Random()
            For i As Integer = 0 To wordArray.Length - 1
                Dim swapIndex As Integer = rand.Next(i + 1)
                Dim temp As String = wordArray(i)
                wordArray(i) = wordArray(swapIndex)
                wordArray(swapIndex) = temp
            Next

            ' We need to stop here to examine results
            ' of all thread activity. This is done in the post-phase
            ' delegate that is defined in the Barrier constructor.
            barrier.SignalAndWait()
        End While
    End Sub
End Class

Barrier es un objeto que impide que las tareas individuales de una operación paralela continúen hasta que todas las tareas alcancen la barrera. Resulta útil cuando se produce una operación paralela en fases y cada fase requiere sincronización entre las tareas. En este ejemplo, hay dos fases para la operación. En la primera fase, cada tarea rellena su sección del búfer con datos. Cuando cada tarea termina de rellenar su sección, la tarea señala la barrera que está lista para continuar y, a continuación, espera. Cuando todas las tareas han señalado la barrera, se desbloquean y comienza la segunda fase. La barrera es necesaria porque la segunda fase requiere que cada tarea tenga acceso a todos los datos generados para este punto. Sin la barrera, las primeras tareas en completarse pueden intentar leer de búferes que otras tareas aún no completaron. Puede sincronizar cualquier número de fases de esta manera.

Consulte también