Synchronisation .NET et EventWaitHandle asynchrone
Dans l'article précédent nous avons évoqué Mutex et les protagonistes de cet article directement ou indirectement Hérite de WaitHandle :
Classe Mutex, dont nous avons déjà parlé dans l'article précédent.
Classe EventWaitHandle et ses classes dérivées AutoResetEvent et ManualResetEvent, c'est le protagoniste de cet article
statiques pour la synchronisation. :
- SignalAndWait(WaitHandle, WaitHandle) : Sous forme d'opération atomique, envoyez un signal au premier WaitHandle et attendez le second, c'est-à-dire réveillez le thread bloqué sur le premier processus WaitHandle. /, puis attendez le deuxième WaitHandle, et ces deux actions sont atomiques, tout comme WaitOne(). Cette méthode a également deux méthodes
surchargées , utilisant respectivement Int32 ou . TimeSpan pour définir le délai d'attente et s'il faut sortir du domaine de synchronisation du contexte
Wait All - (WaitHandle[ ]) : Ceci est utilisé pour attendre tous les membres du tableau WaitHandle
Si une tâche doit attendre que tout le monde soit terminé avant de continuer, cette méthode est toujours un bon choix. Pour les méthodes surchargées permettant de contrôler le délai d'attente, veuillez vous référer. à
WaitAny(WaitHandle[]) : contrairement à WaitAll(), WaitAny attend uniquement qu'un membre du tableau reçoive un signal Return Si vous n'avez besoin d'attendre que l'achèvement le plus rapide. d'un travail, alors WaitAny() est ce dont vous avez besoin
Dépendance du thread
Mutex, comme Monitor, a une dépendance au thread Nous l'avons déjà mentionné, seuls les threads qui ont obtenu le verrou
objet- via Monitor.Enter()/TryEnter() peuvent appeler Pulse()/Wait(). /Exit(); de même, seuls les threads qui obtiennent la propriété Mutex peuvent exécuter la méthode ReleaseMutex(), sinon une exception sera levée. C'est ce qu'on appelle la dépendance aux threads.
En revanche, EventWaitHandle et ses classes dérivées AutoResetEvent et ManualResetEvent sont indépendantes du thread. N'importe quel thread peut signaler à EventWaitHandle de réveiller le thread bloqué dessus.
Le sémaphore qui sera mentionné dans le prochain article est également indépendant des threads.
EventWaitHandle, AutoResetEvent et ManualResetEvent ont tous un « Événement » dans leurs noms, mais ceci est la même chose que le propre mécanisme d'événement de net n'a rien à voir avec cela, il n'implique aucun délégué ou aucune procédure de
gestionnaire d'événement. Par rapport au Monitor et au Mutex que nous avons rencontrés auparavant, qui nécessitent que les threads se disputent les « verrous », nous pouvons les comprendre comme des « événements » qui nécessitent que les threads attendent. Le thread se bloque en attendant que ces événements « se produisent ». Une fois "l'événement" terminé, le thread bloqué peut continuer à fonctionner après avoir reçu le signal. Afin de coopérer avec les trois méthodes statiques SingnalAndWait()/WailAny()/WaitAll() sur WaitHandle, EventWaitHandle fournit sa propre méthode unique pour terminer et redémarrer "Event" :
bool:Set() : version anglaise MSDN : définit l'état de l'événement sur signalé, permettant à un ou plusieurs threads en attente de continuer ; Défini sur l'état terminé, permettant à un ou plusieurs threads en attente de continuer. À première vue, « signalé » et « terminaison » ne semblent pas correspondre, mais à bien y réfléchir, les deux termes ne sont en réalité pas contradictoires. Si l'événement est en cours, bien sûr, il n'y a pas de "termination", alors- les autres
- threads doivent attendre une fois l'événement terminé, alors l'événement est "terminé", nous envoyons donc un signal pour se réveiller ; le fil d'attente, donc le statut "signal envoyé" est également raisonnable. Deux petits détails :
Qu'il s'agisse de la version chinoise ou anglaise, il est mentionné que cette méthode peut faire "continuer/Procéder" "un" ou "plusieurs" threads en attente (attention pas "se réveiller") . Cette méthode est donc similaire à Monitor.Pulse() et Monitor.PulseAll() en termes de « réveil ». Quant à savoir quand il est similaire à Pulse() et quand il est similaire à PulseAll(), lisez la suite.
Cette méthode a une valeur de retour booléenne : true si l'opération réussit ; sinon, false. Cependant, MSDN ne nous indique pas quand l'exécution échouera. Vous pouvez uniquement demander à un Microsoft MVP.
bool:Reset() : Définit l'état de l'événement sur non signalé, provoquant le blocage des threads. Définit l'état de l'événement sur non signalé, provoquant le blocage des threads. De même, nous devons comprendre que « non signalé » et « non terminé » sont la même chose. Encore une fois, il existe toujours une valeur de retour absurde. La fonction de Reset() équivaut à rendre à nouveau l'événement "en cours", puis tous les threads de l'événement WaitOne()/WaitAll()/WaitAny()/SignalAndWait() seront à nouveau bloqués.
Jetons un coup d'œil au constructeur le plus courant de EventWaitHandle Simple :
EventWaitHandle (Boolean initialState, mode EventResetMode) : initialise une nouvelle instance de la classe EventWaitHandle et spécifie si le handle d'attente est initialement dans un état terminé et s'il est réinitialiser automatiquement ou réinitialiser manuellement. La plupart du temps, nous utiliserons false dans le premier paramètre afin que la nouvelle instance passe par défaut à l'état "non terminé". Le deuxième paramètre EventResetMode est une énumération avec un total de deux valeurs :
EventResetMode.AutoReset : Lorsque Set() est appelé, l'EventWaitHandle actuel est transféré vers À l'état terminé, s'il y a un thread bloqué sur le EventWaitHandle actuel, alors après avoir libéré un thread, le EventWaitHandle sera automatiquement réinitialisé (équivalent à appeler automatiquement Reset()) et transféré vers le non- l'état terminé à nouveau, et les threads bloqués restants (le cas échéant) continueront à se bloquer. Si aucun thread n'est bloqué après l'appel de Set(), alors EventWaitHandle restera dans l'état "terminé" jusqu'à ce qu'un thread essaie d'attendre l'événement. Après cela, EventWaitHandle sera automatiquement réinitialisé et bloqué. tous les sujets après ça.
EventResetMode.ManualReset : Une fois terminé, EventWaitHandle libère tous les threads en attente avant la réinitialisation manuelle, c'est-à-dire Reset(). Il reste terminé jusqu'à ce que appelé.
OK, maintenant nous pouvons clairement savoir quand Set() est similaire à Monitor.Pulse()/PulseAll() respectivement :
Lorsque EventWaitHandle fonctionne en mode AutoReset, Set() est similaire à Monitor.Pulse() en termes de fonction de réveil. Pour le moment, Set() ne peut réveiller qu’un des nombreux threads bloqués (s’il y en a plusieurs). Mais il y a quand même quelques différences entre les deux :
La fonction de Set() n'est pas seulement de "réveiller" mais de "libérer", permettant au fil de continuer travailler (continuer) ; au contraire, le thread réveillé par Pulse() ne fait que rentrer dans l'état Running et participe à la compétition pour le verrouillage de l'objet. Personne ne peut garantir qu'il obtiendra le verrouillage de l'objet.
L'état appelé de Pulse() ne sera pas maintenu. Par conséquent, si Pulse() est appelé alors qu'il n'y a aucun thread en attente, le prochain thread qui appelle Monitor.Wait() sera toujours bloqué, comme si Pulse() n'avait jamais été appelé. En d’autres termes, Monitor.Pulse() ne prend effet que lorsqu’il est appelé, contrairement à Set(), qui continuera jusqu’au prochain WaitXXX().
Lorsque la méthode Set() d'un EventWaitHandle fonctionnant en mode ManualReset est appelée, sa fonction de réveil est similaire à Monitor.PulseAll(). Tous les threads sont bloqués. recevez le signal et soyez réveillé. La différence entre les deux est exactement la même que ci-dessus.
Jetons un coup d'œil aux autres constructeurs de EventWaitHandle :
EventWaitHandle(Boolean initialState, EventResetMode mode, String name) : Nous avons déjà vu les deux premiers paramètres, et le nom du troisième paramètre est utilisé pour spécifier les événements de synchronisation à l'échelle du système nom. Oui, comme nous l'avons mentionné dans l'article Mutex, puisque la classe parent WaitHandle a la capacité de traverser des domaines de processus, comme Mutex, nous pouvons créer un EventWaitHandle global et l'utiliser plus tard pour les notifications inter-processus. Notez que le nom est toujours sensible à la casse et qu'il existe toujours des problèmes de préfixe de nom. Vous pouvez vous y référer. Cela équivaut à créer un EventWaitHandle local et sans nom lorsque le nom est null ou string vide. Toujours pareil, il est possible qu'une seule instance soit renvoyée pour représenter l'EventWaitHandle portant le même nom car il existe déjà un EventWaitHandle portant le même nom dans le système. Donc au final, toujours pareil, si vous avez besoin de savoir si cet EventWaitHandle a été créé par vous en premier, vous devez utiliser l'un des deux constructeurs suivants.
EventWaitHandle(Boolean initialState, EventResetMode mode, String name, out BooleancreatedNew) : CreatedNew est utilisé pour indiquer si l'EventWaitHandle a été créé avec succès, true indique le succès , false Indique qu'un événement portant le même nom existe déjà.
EventWaitHandle(Boolean initialState, EventResetMode mode, String name, out BooleancreatedNew, EventWaitHandleSecurity) : concernant les problèmes de sécurité, veuillez vérifier directement l'exemple sur ce constructeur. Les problèmes de sécurité de MutexEventWaitHandle global doivent faire l'objet d'une plus grande attention que ceux de Mutex, car il est possible que des pirates utilisent le même nom d'événement pour envoyer des signaux ou organiser vos threads, ce qui peut sérieusement nuire à votre logique métier.
Démo MSDN
using System;using System.Threading;public class Example { // The EventWaitHandle used to demonstrate the difference // between AutoReset and ManualReset synchronization events. // private static EventWaitHandle ewh; // A counter to make sure all threads are started and // blocked before any are released. A Long is used to show // the use of the 64-bit Interlocked methods. // private static long threadCount = 0; // An AutoReset event that allows the main thread to block // until an exiting thread has decremented the count. // private static EventWaitHandle clearCount = new EventWaitHandle(false, EventResetMode.AutoReset); [MTAThread] public static void Main() { // Create an AutoReset EventWaitHandle. // ewh = new EventWaitHandle(false, EventResetMode.AutoReset); // Create and start five numbered threads. Use the // ParameterizedThreadStart delegate, so the thread // number can be passed as an argument to the Start // method. for (int i = 0; i <= 4; i++) { Thread t = new Thread( new ParameterizedThreadStart(ThreadProc) ); t.Start(i); } // Wait until all the threads have started and blocked. // When multiple threads use a 64-bit value on a 32-bit // system, you must access the value through the // Interlocked class to guarantee thread safety. // while (Interlocked.Read(ref threadCount) < 5) { Thread.Sleep(500); } // Release one thread each time the user presses ENTER, // until all threads have been released. // while (Interlocked.Read(ref threadCount) > 0) { Console.WriteLine("Press ENTER to release a waiting thread."); Console.ReadLine(); // SignalAndWait signals the EventWaitHandle, which // releases exactly one thread before resetting, // because it was created with AutoReset mode. // SignalAndWait then blocks on clearCount, to // allow the signaled thread to decrement the count // before looping again. // WaitHandle.SignalAndWait(ewh, clearCount); } Console.WriteLine(); // Create a ManualReset EventWaitHandle. // ewh = new EventWaitHandle(false, EventResetMode.ManualReset); // Create and start five more numbered threads. // for(int i=0; i<=4; i++) { Thread t = new Thread( new ParameterizedThreadStart(ThreadProc) ); t.Start(i); } // Wait until all the threads have started and blocked. // while (Interlocked.Read(ref threadCount) < 5) { Thread.Sleep(500); } // Because the EventWaitHandle was created with // ManualReset mode, signaling it releases all the // waiting threads. // Console.WriteLine("Press ENTER to release the waiting threads."); Console.ReadLine(); ewh.Set(); } public static void ThreadProc(object data) { int index = (int) data; Console.WriteLine("Thread {0} blocks.", data); // Increment the count of blocked threads. Interlocked.Increment(ref threadCount); // Wait on the EventWaitHandle. ewh.WaitOne(); Console.WriteLine("Thread {0} exits.", data); // Decrement the count of blocked threads. Interlocked.Decrement(ref threadCount); // After signaling ewh, the main thread blocks on // clearCount until the signaled thread has // decremented the count. Signal it now. // clearCount.Set(); } }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Cet article explore les défis des déréférences du pointeur nul dans C. Il soutient que le problème n'est pas nul lui-même, mais son utilisation abusive. L'article détaille les meilleures pratiques pour prévenir les déréférences, y compris les contrôles de pré-déréférence, le pointeur initiali

Cet article explique comment créer de nouvelles caractères en C en C en utilisant la séquence \ n Escape dans printf et met des fonctions. Il détaille les fonctionnalités et fournit des exemples de code démontrant son utilisation pour les ruptures de ligne en sortie.

Cet article guide les débutants sur le choix d'un compilateur C. Il fait valoir que le CCG, en raison de sa facilité d'utilisation, de sa large disponibilité et de ses vastes ressources, est la meilleure pour les débutants. Cependant, il compare également GCC, Clang, MSVC et TCC, mettant en évidence leur différenciation

Cet article met l'accent sur l'importance continue de Null dans la programmation C moderne. Malgré les progrès, NULL reste crucial pour la gestion explicite du pointeur, empêchant les défauts de segmentation en marquant l'absence d'une adresse mémoire valide. Meilleur prac

Cet article passe en revue les compilateurs C en ligne pour les débutants, en se concentrant sur la facilité d'utilisation et les capacités de débogage. Onlinegdb et Rep.Il sont mis en évidence pour leurs interfaces conviviales et leurs outils de débogage utiles. Autres options comme Programiz et Compil

Cet article compare les plateformes de programmation C en ligne, mettant en évidence les différences de fonctionnalités telles que les outils de débogage, les fonctionnalités IDE, la conformité standard et les limites de mémoire / d'exécution. Il soutient que la "meilleure" plate-forme dépend des besoins des utilisateurs,

Cet article traite de la copie de code efficace dans les Cides. Il souligne que la copie est une fonction IDE, pas une fonctionnalité de compilateur, et détaille des stratégies pour une efficacité améliorée, y compris l'utilisation d'outils de sélection IDE, le pliage de code, la recherche / remplacer, Templa

Cet article dépanne les fenêtres de sortie manquantes dans la compilation du programme C. Il examine des causes telles que le non-exécution de l'exécutable, des erreurs de programme, des paramètres de compilateur incorrects, des processus de fond et une terminaison rapide du programme. Les solutions impliquent ch
