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)

Dans le langage C, les caractères spéciaux sont traités à travers des séquences d'échappement, telles que: \ n représente les pauses de ligne. \ t signifie le caractère d'onglet. Utilisez des séquences d'échappement ou des constantes de caractères pour représenter des caractères spéciaux, tels que char c = '\ n'. Notez que l'arrière-plan doit être échappé deux fois. Différentes plates-formes et compilateurs peuvent avoir différentes séquences d'échappement, veuillez consulter la documentation.

En C, le type de char est utilisé dans les chaînes: 1. Stockez un seul caractère; 2. Utilisez un tableau pour représenter une chaîne et se terminer avec un terminateur nul; 3. Faire fonctionner via une fonction de fonctionnement de chaîne; 4. Lisez ou sortant une chaîne du clavier.

Dans le langage C, la principale différence entre Char et WCHAR_T est le codage des caractères: Char utilise ASCII ou étend ASCII, WCHAR_T utilise Unicode; Char prend 1 à 2 octets, WCHAR_T occupe 2-4 octets; Char convient au texte anglais, WCHAR_T convient au texte multilingue; Le char est largement pris en charge, WCHAR_T dépend de la prise en charge du compilateur et du système d'exploitation Unicode; Le char est limité dans la gamme de caractères, WCHAR_T a une gamme de caractères plus grande et des fonctions spéciales sont utilisées pour les opérations arithmétiques.

Les méthodes d'utilisation des symboles dans la couverture du langage C Couverture arithmétique, l'affectation, les conditions, la logique, les opérateurs de bits, etc. Les opérateurs arithmétiques sont utilisés pour les opérations mathématiques de base, les opérateurs d'affectation sont utilisés pour les opérations et les opérations de la soustraction, la multiplication et les opérations de division, les opérations BIT sont utilisé pointeurs nuls, marqueurs de fin de fichier et valeurs non nucères.

La différence entre le multithreading et l'asynchrone est que le multithreading exécute plusieurs threads en même temps, tandis que les opérations effectuent de manière asynchrone sans bloquer le thread actuel. Le multithreading est utilisé pour les tâches à forte intensité de calcul, tandis que de manière asynchrone est utilisée pour l'interaction utilisateur. L'avantage du multi-threading est d'améliorer les performances informatiques, tandis que l'avantage des asynchrones est de ne pas bloquer les threads d'interface utilisateur. Le choix du multithreading ou asynchrone dépend de la nature de la tâche: les tâches à forte intensité de calcul utilisent le multithreading, les tâches qui interagissent avec les ressources externes et doivent maintenir la réactivité de l'interface utilisateur à utiliser asynchrone.

Dans le langage C, la conversion de type char peut être directement convertie en un autre type par: Casting: Utilisation de caractères de casting. Conversion de type automatique: Lorsqu'un type de données peut accueillir un autre type de valeur, le compilateur le convertit automatiquement.

Il n'y a pas de fonction de somme intégrée dans le langage C, il doit donc être écrit par vous-même. La somme peut être obtenue en traversant le tableau et en accumulant des éléments: Version de boucle: la somme est calculée à l'aide de la longueur de boucle et du tableau. Version du pointeur: Utilisez des pointeurs pour pointer des éléments de tableau, et un résumé efficace est réalisé grâce à des pointeurs d'auto-incitation. Allouer dynamiquement la version du tableau: allouer dynamiquement les tableaux et gérer la mémoire vous-même, en veillant à ce que la mémoire allouée soit libérée pour empêcher les fuites de mémoire.

Le Array Char stocke des séquences de caractères en C et est déclaré Char Array_name [Taille]. L'élément d'accès est passé par l'opérateur d'indice, et l'élément se termine par le terminateur nul «\ 0», qui représente le point final de la chaîne. Le langage C fournit une variété de fonctions de manipulation de cordes, telles que strlen (), strcpy (), strcat () et strcmp ().
