Quel est le concept de base derrière WaitHandle?

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 à:

  1. Créer un événement d’attente (object ManualResetEvent)
  2. Enregistrez les événements, WaitHandle.WaitAny(events);
  3. Après avoir effectué l’opération dans votre thread, le .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 AutoResetEventAutoResetEvent ” 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.