Condividi tramite


Procedura: sincronizzare operazioni simultanee con una barriera

Nell'esempio seguente viene mostrato come sincronizzare attività simultanee con un oggetto Barrier.

Esempio

Lo scopo del programma seguente è contare le iterazioni (o fasi) necessarie per due thread affinché per ciascuno di essi venga trovata la relativa metà della soluzione nella stessa fase utilizzando un algoritmo di casualità per riprodurre con sequenza casuale le parole. Una volta che ciascun thread ha riprodotto con sequenza casuale le proprie parole, l'operazione post-fase della barriera confronta i due risultati per verificare se è stato eseguito il rendering della frase completa nell'ordine delle parole corretto.

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks


    Class Program
        Shared words1() = New String() {"brown", "jumped", "the", "fox", "quick"}
        Shared words2() = New String() {"dog", "lazy", "the", "over"}
        Shared solution = "the quick brown fox jumped 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
//#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",  "jumped", "the", "fox", "quick"};
        static string[] words2 = new string[] { "dog", "lazy","the","over"};
        static string solution = "the quick brown fox jumped 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();
            }
        }
    }
}

Gli oggetti Barrier impediscono l'esecuzione di singole attività in un'operazione in parallelo finché tutte le attività non raggiungono la barriera. Questo approccio risulta utile quando un'operazione in parallelo prevede più fasi e per ogni fase occorre garantire la sincronizzazione tra le attività. In questo esempio l'operazione prevede due fasi. Nella prima fase, ogni attività riempie la propria sezione del buffer con dati. Quando un'attività completa il riempimento della propria sezione, indica alla barriera che è pronta a continuare e quindi resta in attesa. Quando tutte le attività hanno eseguito questa operazione, vengono sbloccate e inizia la seconda fase. La barriera è necessaria poiché nella seconda fase ogni attività deve essere in grado di accedere a tutti i dati generati fino alla fine della prima fase. Senza la barriera, le prime attività che completano la prima fase potrebbero tentare di leggere dati da buffer che ancora non sono stati riempiti dalle altre attività. In questo modo è possibile sincronizzare il numero desiderato di fasi.

Vedere anche

Concetti

Strutture di dati per la programmazione in parallelo