71 votes

Quel est le concept de base derrière WaitHandle?

Quel est le concept de base derrière WaitHandle en threading C # .net? Quel est son usage? Quand l'utiliser? Quelle est l'utilisation des méthodes WaitAll et WaitAny à l' intérieur?

63voto

KMån Points 7972

Chaque fois que vous voulez contrôler l'exécution de plusieurs threads dans votre application. Bien que cela ne signifie pas seulement qu'un seul thread incrémente le compteur; mais laissez-le fils démarrer/arrêter ou mettre en pause lors d'un événement.

Voir WaitHandles - Auto/ManualResetEvent et Mutex

--EDIT--

WaitHandles sont le mécanisme que vous "utilisez" pour contrôler les threads d'exécution. Ce n'est pas sur les poignées ne sont pas accessibles dans un thread; son sujet de leur utilisation dans le thread.

Cela peut être une matière grasse, par exemple, mais s'il vous plaît garder avec moi; penser, une dame donne cinq différents tons de sifflets à cinq filles, et leur dit de siffler à chaque fois qu' something arriverait-il; le processus est pour chaque fille à coup un coup de sifflet, et la dame serait de savoir qui a fait exploser le coup de sifflet.

Maintenant, ce n'est pas sur le partage-la-sifflets les uns avec les autres, son sujet, probablement pour la dame, pour les utiliser afin de "contrôler" l'exécution ou le processus de la façon dont les filles se serait un coup de sifflet.

Donc, techniquement, le processus serait le suivant:

  1. Créer une attente de l'événement(ManualResetEvent objet)
  2. Enregistrer les événements, WaitHandle.WaitAny(events);
  3. Après vous avez terminé d'effectuer l'opération dans votre fil, l' .Set(), ce qui permettrait de dire que le WaitHandle que " je suis terminé!'.

Par exemple, prenons l'exemple du lien fourni. J'ai ajouté les étapes pour vous de comprendre la logique. Ce ne sont pas codées en dur étapes, mais juste pour que vous puissiez le comprendre.

class Test
{
    static void Main()
    {
    //STEP 1: Create a wait handle
        ManualResetEvent[] events = new ManualResetEvent[10];//Create a wait handle
        for (int i=0; i < events.Length; i++)
        {
            events[i] = new ManualResetEvent(false);
            Runner r = new Runner(events[i], i); 
            new Thread(new ThreadStart(r.Run)).Start();
        }

    //STEP 2: Register for the events to wait for
        int index = WaitHandle.WaitAny(events); //wait here for any event and print following line.

        Console.WriteLine ("***** The winner is {0} *****", 
                           index);

        WaitHandle.WaitAll(events); //Wait for all of the threads to finish, that is, to call their cooresponding `.Set()` method.

        Console.WriteLine ("All finished!");
    }
}


class Runner
{
    static readonly object rngLock = new object();
    static Random rng = new Random();

    ManualResetEvent ev;
    int id;

    internal Runner (ManualResetEvent ev, int id)
    {
        this.ev = ev;//Wait handle associated to each object, thread in this case.
        this.id = id;
    }

    internal void Run()
    {
    //STEP 3: Do some work
        for (int i=0; i < 10; i++)
        {
            int sleepTime;
            // Not sure about the thread safety of Random...
            lock (rngLock)
            {
                sleepTime = rng.Next(2000);
            }
            Thread.Sleep(sleepTime);
            Console.WriteLine ("Runner {0} at stage {1}",
                               id, i);
        }

    //STEP 4: Im done!
        ev.Set();
    }
}

36voto

Adam Robinson Points 88472

WaitHandle est une classe de base abstraite pour les deux couramment utilisés événement poignées: AutoResetEvent et ManualResetEvent.

Deux de ces classes permettent un fil pour le "signal" de l'un ou de plusieurs autres threads. Ils sont utilisés pour synchroniser (ou sérialiser activité) entre les threads. Ceci est accompli en utilisant l' Set et WaitOne (ou WaitAll) des méthodes. Par exemple:

Thread 1:

// do setup work

myWaitHandle.Set();

Filetage 2:

// do setup work

myWaitHandle.WaitOne();

// this code will not continue until after the call to `Set` 
// in thread 1 completes.

C'est un très rudimentaire exemple, et il y en a beaucoup de disponibles sur le web. L'idée de base est qu' WaitOne est utilisé pour attendre un signal à partir d'un autre thread qui indique que quelque chose s'est passé. Dans le cas d' AsyncWaitHandle (qui est retourné par l'invocation d'un délégué de façon asynchrone), WaitOne permet de provoquer le thread en cours d'attendre jusqu'à ce que l'opération asynchrone est terminée.

Lorsqu'un AutoResetEvent ou ManualResetEvent ne sont pas définies, les appels à l' WaitOne va bloquer le thread appelant jusqu' Set est appelé. Ces deux classes diffèrent seulement en ce qu' AutoResetEvent "unsets" le cas une fois qu'un appel à l' WaitOne terminée, faire des appels ultérieurs bloc de nouveau jusqu' Set est appelé. ManualResetEvent doit être "unset" explicitement en appelant Reset.

WaitAll et WaitAny sont des méthodes statiques de l' WaitHandle de la classe qui vous permettent de spécifier un tableau de WaitHandles à attendre. WaitAll bloquera jusqu'à ce que toutes les poignées sont fournies Set, alors que WaitAny ne bloque jusqu'à ce que l'un d'eux se Set.

10voto

Hans Passant Points 475940

C'est une classe abstraite, vous ne l'utilisez pas directement. De béton les classes dérivées sont ManualResetEvent, AutoResetEvent, Mutex et Sémaphore. Important classes dans votre boîte à outils pour mettre en œuvre la synchronisation des threads. Ils héritent de la WaitOne, WaitAll et WaitAny méthodes, de les utiliser pour détecter un ou plusieurs threads signalé la condition d'attente.

Scénario d'utilisation habituelle pour Manuel/AutoResetEvent est-à-dire un fil à la sortie ou à laisser un fil de signal qu'il a progressé à un important point de séquence. Sémaphore vous aide à limiter le nombre de threads d'exécuter une action. Ou pour mettre en œuvre le filetage de synchronisation ne doit pas avoir d'affinité à un fil. Mutex est là pour en attribuer la propriété à une section de code à un fil, l'instruction lock est souvent applicable aussi bien.

Des livres ont été écrits sur le sujet. Joe Duffy Simultané la Programmation de Windows est la dernière et la plus grande. Fortement recommandé si vous contempler l'écriture fileté code.

8voto

Joel Coehoorn Points 190579

L'idée derrière le WaitAll et WaitAny méthodes, c'est qu'ils sont utiles lorsque vous avez beaucoup de tâches que vous souhaitez exécuter en parallèle.

Par exemple, disons que vous avez un emploi qui vous oblige de faire le traitement pour un 1000 éléments dans un tableau qui doivent être traitées en parallèle. Un Core 2 Duo + hyperthreading a seulement 4 processeurs logiques, et donc il ne fait pas beaucoup de sens d'avoir plus de 4 threads va à la fois (en fait, il le fait, mais c'est une autre histoire -, nous allons faire semblant et de l'utilisation de la simple "threads par processeur" modèle pour l'instant). Donc 4 fils, mais 1000 articles; que faites-vous?

Une option est d'utiliser le WaitAny méthode. Vous le coup d'envoi de 4 threads, et chaque fois que le WaitAny méthode retourne vous le coup d'envoi de l'autre, jusqu'à ce que tous les 1 000 articles sont mis en file d'attente. Notez que c'est un mauvais exemple pour WaitAny, car vous pourriez tout aussi bien diviser votre groupe en 250 élément de blocs. Heureusement, bien que, cela vous donne une idée du genre de situation où WaitAny est utile. Il y a d'autres situations similaires où WaitAny peut faire beaucoup de sens.

Mais revenons au scénario avec 4 fils de chaque processus de 250 articles de votre 1000 élément de tableau. Avec cette option, vous pouvez utiliser le WaitAll méthode attendre que tous les la fin du traitement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X