Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
La EventWaitHandle classe permet aux threads de communiquer entre eux en signalant et en attendant les signaux. Les handles d’attente d’événement (également appelés simplement des événements) sont des handles d’attente qui peuvent être signalés pour libérer un ou plusieurs threads en attente. Une fois signalé, un handle d’attente d’événement est réinitialisé manuellement ou automatiquement. La EventWaitHandle classe peut représenter un handle d’attente d’événement local (événement local) ou un handle d’attente d’événement système nommé (événement nommé ou événement système, visible pour tous les processus).
Remarque
Les handles d’attente d’événement ne sont pas des événements .NET. Aucun délégué ou gestionnaire d’événements n’est impliqué. Le mot « événement » est utilisé pour les décrire parce qu’ils ont traditionnellement été appelés événements de système d’exploitation, et parce que l’acte de signalisation du handle d’attente indique aux threads en attente qu’un événement s’est produit.
Les handles d’attente d’événement locaux et nommés utilisent des objets de synchronisation du système, qui sont protégés par des wrappers SafeWaitHandle pour garantir la libération des ressources. Vous pouvez utiliser la Dispose méthode pour libérer les ressources immédiatement lorsque vous avez terminé d’utiliser l’objet.
Handles d’attente d’événement à réinitialisation automatique
Vous créez un événement de réinitialisation automatique en spécifiant EventResetMode.AutoReset quand vous créez l’objet EventWaitHandle . Comme son nom l’indique, cet événement de synchronisation est réinitialisé automatiquement lorsqu’il est signalé, après avoir libéré un seul thread en attente. Signalez l’événement en appelant sa Set méthode.
Les événements de réinitialisation automatique sont généralement utilisés pour fournir un accès exclusif à une ressource pour un thread unique à la fois. Un thread demande la ressource en appelant la WaitOne méthode. Si aucun autre thread ne contient le handle d’attente, la méthode retourne true et le thread appelant a le contrôle de la ressource.
Importante
Comme pour tous les mécanismes de synchronisation, vous devez vous assurer que tous les chemins de code attendent le signal d'attente approprié avant d'accéder à une ressource protégée. La synchronisation de threads est coopérative.
Si un événement à réinitialisation automatique est signalé alors qu’aucun thread n’attend, il reste signalé jusqu'à ce qu’un thread tente de l’attendre. L’événement libère le thread et réinitialise immédiatement, bloquant les threads suivants.
Handles d’attente d’événement à réinitialisation manuelle
Vous créez un événement de réinitialisation manuelle en spécifiant EventResetMode.ManualReset quand vous créez l’objet EventWaitHandle . Comme son nom l’indique, cet événement de synchronisation doit être réinitialisé manuellement une fois qu’il a été signalé. Jusqu'à sa réinitialisation, en appelant sa méthode Reset, les threads qui attendent le handle d’événement continuent immédiatement, sans blocage.
Un événement manuel agit comme la barrière d’un corral. Quand l’événement n’est pas signalé, les threads qui l’attendent sont bloqués, comme les chevaux dans un corral. Lorsque l’événement est signalé, en appelant sa Set méthode, tous les threads en attente sont libres de continuer. L’événement reste signalé jusqu’à ce que sa Reset méthode soit appelée. L’événement à réinitialisation manuelle est par conséquent un moyen idéal de retenir les threads qui doivent attendre jusqu'à ce qu’un thread termine une tâche.
Comme les chevaux quittant un corral, il faut du temps pour que les threads libérés soient planifiés par le système d’exploitation et recommencent à s’exécuter. Si la Reset méthode est appelée avant que tous les threads aient repris l’exécution, les threads restants sont à nouveau bloqués. Quels threads reprennent et quels threads bloquent dépendent de facteurs aléatoires tels que la charge sur le système, le nombre de threads en attente du planificateur, etc. Ce n’est pas un problème si le thread qui signale l’événement se termine après la signalisation, qui est le modèle d’utilisation le plus courant. Si vous souhaitez que le thread signalant l’événement commence une nouvelle tâche une fois que tous les threads en attente ont repris, vous devez le bloquer jusqu’à ce que tous les threads en attente aient repris. Dans le cas contraire, il existe une condition de concurrence et le comportement de votre code est imprévisible.
Fonctionnalités communes aux événements automatiques et manuels
En règle générale, un ou plusieurs threads bloquent un EventWaitHandle thread jusqu’à ce qu’un thread débloqué appelle la Set méthode, ce qui libère l’un des threads en attente (dans le cas d’événements de réinitialisation automatique) ou tous (en cas d’événements de réinitialisation manuelle). Un thread peut signaler un EventWaitHandle, puis se bloquer sur celui-ci, comme une opération atomique, en appelant la méthode statique WaitHandle.SignalAndWait.
EventWaitHandle les objets peuvent être utilisés avec les méthodes statiques WaitHandle.WaitAll et WaitHandle.WaitAny. Étant donné que les EventWaitHandle classes et Mutex les deux dérivent de WaitHandle, vous pouvez utiliser les deux classes avec ces méthodes.
Événements nommés
Le système d’exploitation Windows permet aux handles d’attente d’événements d’avoir des noms. Un événement nommé s'applique à l'ensemble du système. Autrement dit, une fois que l’événement nommé a été créé, il est visible par tous les threads de tous les processus. Ainsi, les événements nommés peuvent être utilisés pour synchroniser les activités des processus ainsi que les threads.
Vous pouvez créer un EventWaitHandle objet qui représente un événement système nommé à l’aide de l’un des constructeurs qui spécifie un nom d’événement.
Remarque
Étant donné que les événements nommés sont à l’échelle du système, il est possible d’avoir plusieurs EventWaitHandle objets qui représentent le même événement nommé. Chaque fois que vous appelez un constructeur ou la OpenExisting méthode, un nouvel EventWaitHandle objet est créé. La spécification du même nom crée plusieurs objets qui représentent le même événement nommé.
Il est conseillé de faire preuve de prudence lors de l'utilisation des événements nommés. Étant donné qu’ils sont à l’échelle du système, un autre processus qui utilise le même nom peut bloquer vos threads de manière inattendue. Le code malveillant s’exécutant sur le même ordinateur peut l’utiliser comme base d’une attaque par déni de service.
Utilisez la sécurité du contrôle d’accès pour protéger un EventWaitHandle objet qui représente un événement nommé, de préférence à l’aide d’un constructeur qui spécifie un EventWaitHandleSecurity objet. Vous pouvez également appliquer la sécurité du contrôle d’accès à l’aide de la SetAccessControl méthode, mais cela laisse une fenêtre de vulnérabilité entre le moment où le handle d’attente d’événement est créé et le moment où il est protégé. La protection des événements à l’aide de la sécurité de contrôle d'accès empêche les attaques malveillantes, mais ne résout pas le problème des conflits de noms involontaires.
Remarque
Contrairement à la classe EventWaitHandle, les classes dérivées AutoResetEvent et ManualResetEvent peuvent représenter uniquement les handles d’attente locaux. Elles ne peuvent pas représenter des événements système nommés.