Quel est le concept de base derrière WaitHandle
dans les WaitHandle
C # .net? Quelle est son utilisation? Quand l’utiliser? A quoi servent les méthodes WaitAll et WaitAny ?
Chaque fois que vous souhaitez 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 les threads démarrer / arrêter ou suspendre un événement.
Voir WaitHandles – Auto / ManualResetEvent et Mutex
–MODIFIER–
WaitHandle
s sont le mécanisme que vous “utilisez” pour contrôler l’exécution des threads. Il ne s’agit pas de poignées non accessibles dans un fil; c’est à propos de les utiliser dans le fil.
Cela peut être un gros exemple, mais s’il vous plaît supportez avec moi; pense à, une dame donne cinq sifflets toniques différents à cinq filles, et leur dit de siffler chaque fois que something
se passerait; le processus consiste à siffler chaque fille et la dame sait qui a sifflé.
Maintenant, il ne s’agit pas de partager les sifflets les uns avec les autres, c’est probablement pour la femme de les utiliser pour «contrôler» l’exécution ou le processus de dénonciation des filles.
Par conséquent, techniquement, le processus consisterait à:
WaitHandle.WaitAny(events);
.Set()
, qui indiquerait au WaitHandle que “je suis fait!”. Par exemple, prenons l’exemple du lien fourni. J’ai ajouté les étapes pour vous permettre de comprendre la logique. Ce ne sont pas les étapes codées en dur, mais juste pour que vous puissiez 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 AutoResetEvent
événement couramment utilisés: AutoResetEvent
et ManualResetEvent
.
Ces deux classes permettent à un thread de “signaler” un ou plusieurs autres threads. Ils sont utilisés pour synchroniser (ou sérialiser l’activité) entre les threads. Ceci est accompli en utilisant les méthodes Set
et WaitOne
(ou WaitAll
). Par exemple:
Fil 1:
// do setup work myWaitHandle.Set();
Fil 2:
// do setup work myWaitHandle.WaitOne(); // this code will not continue until after the call to `Set` // in thread 1 completes.
Ceci est un exemple très rudimentaire, et il en existe beaucoup sur le Web. L’idée de base est que WaitOne
est utilisé pour attendre un signal d’un autre thread qui indique que quelque chose est arrivé. Dans le cas d’ AsyncWaitHandle
(renvoyé par l’appel asynchrone d’un délégué), WaitOne
vous permet d’attendre que le thread en cours soit terminé.
Lorsqu’un AutoResetEvent
ou ManualResetEvent
n’est pas défini, les appels à WaitOne
bloquent le thread d’appel jusqu’à ce que Set
soit appelé. Ces deux classes diffèrent uniquement par le fait que AutoResetEvent
” AutoResetEvent
” l’événement une fois l’appel de WaitOne
terminé, rendant les appels suivants à nouveau WaitOne
jusqu’à l’appel de Set
. ManualResetEvent
doit être “désactivé” explicitement en appelant Reset
.
WaitAll
et WaitAny
sont des méthodes statiques sur la classe WaitHandle
qui vous permettent de spécifier un tableau de WaitHandles
à attendre. WaitAll
bloquera jusqu’à ce que tous les WaitAll
fournis soient WaitAny
, alors que WaitAny
ne bloquera que lorsque l’ un d’entre eux aura atteint Set
.
C’est une classe abstraite, vous ne l’utilisez pas directement. Les classes dérivées concrètes sont ManualResetEvent, AutoResetEvent, Mutex et Semaphore. Classes importantes dans votre boîte à outils pour implémenter la synchronisation des threads. Ils héritent des méthodes WaitOne, WaitAll et WaitAny, vous les utilisez pour détecter qu’un ou plusieurs threads ont signalé la condition d’attente.
Le scénario d’utilisation typique de Manual / AutoResetEvent consiste à dire à un thread de quitter ou de laisser un thread signaler qu’il a progressé vers un sharepoint séquence important. Sémaphore vous aide à limiter le nombre de threads qui effectuent une action. Ou pour implémenter la synchronisation de threading qui ne devrait pas avoir d’affinité pour un thread particulier. Mutex est là pour atsortingbuer la propriété à une section de code à un thread, l’instruction de locking y est souvent également applicable.
Des livres ont été écris à ce sujet. La programmation simultanée de Joe Duffy sous Windows est la plus récente et la plus performante. Fortement recommandé si vous envisagez d’écrire du code threadé.
Imaginez que vous ayez un tableau contenant 1000 éléments. Vous devez effectuer un traitement sur chacun de ces éléments. Ce travail prendra du temps, mais n’est pas lié aux E / S.
Par exemple, vous devez peut-être utiliser chaque élément pour effectuer une requête Web à faible bande passante. Vous disposez de beaucoup de débit pour demander plusieurs éléments en même temps, et la latence de chaque requête Web signifie qu’il faudra plus de temps pour en effectuer une à la fois.
Entrez dans le monde de la programmation parallèle. Aujourd’hui, il existe plusieurs façons de gérer cette tâche, et WaitHandle
fait partie intégrante. Même si vous n’utilisez pas directement WaitHandle
, les options que vous choisissez dépendent probablement d’un WaitHandle
tel que WaitAll
ou WaitAny
dans les coulisses.
En reprenant l’exemple, supposons que vous ayez un processeur à quatre cœurs typique. Dans cette situation, il n’est pas logique d’avoir plus de 4 threads à la fois. * Donc 4 fils, mais 1000 éléments; Que faire?
Une option utilise WaitAny
. Vous WaitAny
4 threads, et chaque fois que la méthode WaitAny
vous renvoie, vous en lancez un autre, jusqu’à ce que tous les 1000 éléments soient mis en queue. Notez que ceci est un mauvais exemple pour WaitAny
, car nous connaissons le nombre total d’éléments disponibles et pouvons accéder à tous les éléments au même rythme. WaitAny
est préférable lorsque vous avez uniquement un access séquentiel. Il y a d’autres situations similaires où WaitAny
peut avoir beaucoup de sens.
Une autre option utilise WaitAll
. Au lieu de mettre en queue un élément à la fois, vous définissez un thread pour chacun des quatre cœurs. Atsortingbuez-lui un segment différent de 250 éléments du tableau. Avec cette option, vous pouvez utiliser WaitAll
pour attendre la fin du traitement.
* En fait, c’est le cas. Il y a généralement un certain temps d’E / S où le processeur est inactif, de sorte que vous pouvez faire mieux en ayant plus d’un thread par cœur. Mais c’est une histoire pour une autre fois.
Il y a de très longues réponses ici. Pour ceux qui recherchent la réponse courte:
Wait handle est un mécanisme permettant d’attendre qu’un autre thread atteigne un certain point.
Vous pouvez également avoir plusieurs threads en attente et / ou plusieurs threads en attente, d’où les WaitOne
, WaitAll
et WaitAny
. Il existe également plusieurs options de sémantique disponibles en choisissant l’une de ces classes: Mutex
, Semaphore
, ManualResetEvent
, AutoResetEvent
qui sont bien documentées.