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?
Réponses
Trop de publicités?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--
WaitHandle
s 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:
- Créer une attente de l'événement(ManualResetEvent objet)
- Enregistrer les événements,
WaitHandle.WaitAny(events);
- 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();
}
}
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
.
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.
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.