Exporter (0) Imprimer
Développer tout
Cet article a fait l'objet d'une traduction automatique. Déplacez votre pointeur sur les phrases de l'article pour voir la version originale de ce texte. Informations supplémentaires.
Traduction
Source

Comment : synchroniser des opérations simultanées avec un objet Barrier

L'exemple suivant indique comment synchroniser des tâches simultanées avec un Barrier.

L'objectif du programme suivant est de compter le nombre d'itérations (ou phases) nécessaires pour que deux threads trouvent leur moitié de solution sur la même phase à l'aide d'un algorithme aléatoire pour réorganiser l'ordre des mots. Une fois que chaque thread a mélangé ses mots, l'opération post-phase de cloisonnement compare les deux résultats pour voir si la phrase complète a été restituée avec les mots dans le bon ordre.


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


Un Barrier est un objet qui empêche des tâches individuelles dans une opération en parallèle de continuer jusqu'à ce que toutes les tâches atteignent le cloisonnement. Cela est utile lorsqu'une opération en parallèle se produit par phases et que chaque phase requiert la synchronisation entre les tâches. Dans cet exemple, l'opération se déroule en deux phases. Lors de la première phase, chaque tâche remplit sa section de la mémoire tampon avec des données. Une fois que chaque tâche a rempli sa section, elle signale au cloisonnement qu'elle est prête à continuer, puis attend. Lorsque toutes les tâches ont prévenu le cloisonnement, elles sont débloquées et la deuxième phase démarre. Le cloisonnement est nécessaire car la seconde phase requiert que chaque tâche ait accès à toutes les données déjà générées. Sans le cloisonnement, les premières tâches à avoir terminé peuvent essayer de lire à partir de mémoires tampons qui n'ont pas encore été remplies par les tâches. Vous pouvez synchroniser de cette manière n'importe quel nombre de phases.

Ajouts de la communauté

AJOUTER
Afficher:
© 2014 Microsoft