Delen via


EventWaitHandle

Met de EventWaitHandle klasse kunnen threads met elkaar communiceren door te signaleren en te wachten op signalen. Gebeurteniswachtingangen (ook wel gewoon gebeurtenissen genoemd) zijn wachtgrepen die kunnen worden gesignaleerd om een of meer wachtthreads vrij te geven. Nadat deze is gesignaleerd, wordt een wachtgreep voor gebeurtenissen handmatig of automatisch opnieuw ingesteld. De EventWaitHandle klasse kan een wachtgreep voor een lokale gebeurtenis (lokale gebeurtenis) of een benoemde gebeurteniswachtingsgreep (benoemde gebeurtenis of systeembeurtenis, zichtbaar voor alle processen) vertegenwoordigen.

Notitie

Wachtingangen voor gebeurtenissen zijn geen .NET-gebeurtenissen. Er zijn geen gemachtigden of gebeurtenis-handlers betrokken. Het woord 'gebeurtenis' wordt gebruikt om ze te beschrijven omdat ze traditioneel worden aangeduid als gebeurtenissen van het besturingssysteem, en omdat de handeling van het signaleren van de wachtgreep aangeeft dat er threads zijn die een gebeurtenis heeft plaatsgevonden.

Zowel lokale als benoemde wachtgrepen maken gebruik van systeemsynchronisatieobjecten, die worden beveiligd door SafeWaitHandle wrappers om ervoor te zorgen dat de resources worden vrijgegeven. U kunt de Dispose methode gebruiken om de resources onmiddellijk vrij te maken wanneer u klaar bent met het gebruik van het object.

Gebeurteniswachtingangen die automatisch opnieuw worden ingesteld

U maakt een gebeurtenis voor automatisch opnieuw instellen door op te EventResetMode.AutoReset geven wanneer u het EventWaitHandle object maakt. Zoals de naam al aangeeft, wordt deze synchronisatiegebeurtenis automatisch opnieuw ingesteld wanneer deze wordt gesignaleerd, na het vrijgeven van één wachtende thread. Signaler de gebeurtenis door de methode aan Set te roepen.

Gebeurtenissen voor automatisch opnieuw instellen worden meestal gebruikt om exclusieve toegang tot een resource voor één thread tegelijk te bieden. Een thread vraagt de resource aan door de WaitOne methode aan te roepen. Als er geen andere thread de wachtgreep vasthoudt, retourneert true de methode en heeft de aanroepende thread controle over de resource.

Belangrijk

Net als bij alle synchronisatiemechanismen moet u ervoor zorgen dat alle codepaden wachten op de juiste wachtgreep voordat u toegang krijgt tot een beveiligde resource. Threadsynchronisatie is coöperatief.

Als een gebeurtenis voor automatisch opnieuw instellen wordt gesignaleerd wanneer er geen threads wachten, blijft deze gesignaleerd totdat een thread erop probeert te wachten. Met de gebeurtenis wordt de thread vrijgegeven en onmiddellijk opnieuw ingesteld, waardoor volgende threads worden geblokkeerd.

Gebeurteniswachtingangen die handmatig opnieuw worden ingesteld

U maakt een handmatige reset-gebeurtenis door op te EventResetMode.ManualReset geven wanneer u het EventWaitHandle object maakt. Zoals de naam al aangeeft, moet deze synchronisatiegebeurtenis handmatig opnieuw worden ingesteld nadat deze is gesignaleerd. Totdat de methode opnieuw is ingesteld, Reset worden threads die wachten op de gebeurtenisgreep onmiddellijk zonder blokkering uitgevoerd.

Een handmatige reset-gebeurtenis fungeert als de poort van een corral. Wanneer de gebeurtenis niet wordt gesignaleerd, threads die wachten op het blok, zoals paarden in een corral. Wanneer de gebeurtenis wordt gesignaleerd door de Set methode aan te roepen, zijn alle wachtende threads vrij om door te gaan. De gebeurtenis blijft gesignaleerd totdat de Reset methode wordt aangeroepen. Hierdoor is de gebeurtenis voor handmatig opnieuw instellen een ideale manier om threads vast te houden die moeten wachten totdat één thread een taak heeft voltooid.

Net als paarden die een corral verlaten, duurt het even voordat de uitgebrachte threads door het besturingssysteem worden gepland en de uitvoering hervat. Als de Reset methode wordt aangeroepen voordat alle threads de uitvoering hebben hervat, worden de resterende threads opnieuw geblokkeerd. Welke threads worden hervat en welke threads blokkeren, is afhankelijk van willekeurige factoren, zoals de belasting van het systeem, het aantal threads dat op de scheduler wacht, enzovoort. Dit is geen probleem als de thread die de gebeurtenis aangeeft, eindigt na signalering. Dit is het meest voorkomende gebruikspatroon. Als u wilt dat de thread die de gebeurtenis heeft gesignaleerd, een nieuwe taak start nadat alle wachtende threads zijn hervat, moet u deze blokkeren totdat alle wachtende threads zijn hervat. Anders hebt u een racevoorwaarde en is het gedrag van uw code onvoorspelbaar.

Functies die gebruikelijk zijn voor automatische en handmatige gebeurtenissen

Normaal gesproken worden een of meer threads geblokkeerd op een EventWaitHandle totdat een niet-geblokkeerde thread de Set methode aanroept, waardoor een van de wachtende threads (in het geval van automatische resetgebeurtenissen) of alle threads (in het geval van handmatige resetgebeurtenissen) wordt vrijgegeven. Een thread kan een EventWaitHandle signaal geven en vervolgens blokkeren, als atomische bewerking, door de statische WaitHandle.SignalAndWait methode aan te roepen.

EventWaitHandle objecten kunnen worden gebruikt met de statische WaitHandle.WaitAll en WaitHandle.WaitAny methoden. Omdat de EventWaitHandle en Mutex klassen beide zijn afgeleid van WaitHandle, kunt u beide klassen met deze methoden gebruiken.

Benoemde gebeurtenissen

Met het Windows-besturingssysteem kunnen wachtgrepen voor gebeurtenissen namen hebben. Een benoemde gebeurtenis is systeembreed. Zodra de benoemde gebeurtenis is gemaakt, is deze zichtbaar voor alle threads in alle processen. Benoemde gebeurtenissen kunnen dus worden gebruikt om de activiteiten van processen en threads te synchroniseren.

U kunt een EventWaitHandle object maken dat een benoemde systeem gebeurtenis vertegenwoordigt met behulp van een van de constructors die een gebeurtenisnaam opgeeft.

Notitie

Omdat benoemde gebeurtenissen systeembreed zijn, is het mogelijk om meerdere EventWaitHandle objecten te hebben die dezelfde benoemde gebeurtenis vertegenwoordigen. Telkens wanneer u een constructor aanroept of de OpenExisting methode, wordt er een nieuw EventWaitHandle object gemaakt. Als u dezelfde naam opgeeft, worden meerdere objecten gemaakt die dezelfde benoemde gebeurtenis vertegenwoordigen.

Let op bij het gebruik van benoemde gebeurtenissen. Omdat ze systeembreed zijn, kan een ander proces dat dezelfde naam gebruikt, uw threads onverwacht blokkeren. Schadelijke code die op dezelfde computer wordt uitgevoerd, kan dit gebruiken als basis van een denial-of-service-aanval.

Gebruik de beveiliging van toegangsbeheer om een EventWaitHandle object te beveiligen dat een benoemde gebeurtenis vertegenwoordigt, bij voorkeur met behulp van een constructor die een EventWaitHandleSecurity object opgeeft. U kunt ook de beveiliging van toegangsbeheer toepassen met behulp van de SetAccessControl methode, maar dit laat een beveiligingsvenster achter tussen het moment waarop de gebeurteniswachting wordt gemaakt en de tijd waarop deze is beveiligd. Het beveiligen van gebeurtenissen met beveiliging voor toegangsbeheer helpt schadelijke aanvallen te voorkomen, maar lost het probleem van onbedoelde naamconflicten niet op.

Notitie

In tegenstelling tot de EventWaitHandle klasse kunnen de afgeleide klassen AutoResetEvent alleen ManualResetEvent lokale wachtgrepen vertegenwoordigen. Ze kunnen geen benoemde systeemevenementen vertegenwoordigen.

Zie ook