Udostępnij za pośrednictwem


EventWaitHandle

Klasa EventWaitHandle umożliwia wątkom komunikowanie się ze sobą przez sygnalizowanie i oczekiwanie na sygnały. Dojścia oczekiwania zdarzeń (nazywane również po prostu zdarzeniami) to dojścia oczekiwania, które mogą być sygnalizowane w celu zwolnienia co najmniej jednego wątku oczekującego. Gdy zostanie zasygnalizowany, dojście oczekiwania na zdarzenia zostanie zresetowane ręcznie lub automatycznie. Klasa EventWaitHandle może reprezentować lokalny uchwyt oczekiwania zdarzeń (zdarzenie lokalne) lub nazwany uchwyt oczekiwania zdarzeń systemowych (nazwane zdarzenie lub zdarzenie systemowe, widoczne dla wszystkich procesów).

Uwaga

Dojścia oczekiwania zdarzeń nie są zdarzeniami platformy .NET. Nie ma żadnych delegatów ani programów obsługi zdarzeń. Słowo "zdarzenie" służy do opisywania ich, ponieważ tradycyjnie było określane jako zdarzenia systemu operacyjnego, a ponieważ czynność sygnalizowania uchwytu oczekiwania wskazuje na oczekujące wątki, które wystąpiło zdarzenie.

Zarówno lokalne, jak i nazwane dojścia oczekiwania na zdarzenia używają obiektów synchronizacji systemu, które są chronione przez SafeWaitHandle otoki, aby upewnić się, że zasoby są zwalniane. Możesz użyć Dispose metody , aby zwolnić zasoby natychmiast po zakończeniu korzystania z obiektu.

Usługa Event Wait obsługuje automatyczne resetowanie

Zdarzenie automatycznego resetowania jest tworzone przez określenie EventResetMode.AutoReset podczas tworzenia EventWaitHandle obiektu. Jak wskazuje jego nazwa, to zdarzenie synchronizacji jest resetowane automatycznie po zasygnaliowaniu, po zwolnieniu pojedynczego wątku oczekiwania. Zasygnalizuj zdarzenie, wywołując jego Set metodę.

Zdarzenia automatycznego resetowania są zwykle używane do zapewnienia wyłącznego dostępu do zasobu dla pojedynczego wątku naraz. Wątek żąda zasobu, wywołując metodę WaitOne . Jeśli żaden inny wątek nie przechowuje uchwytu oczekiwania, metoda zwraca true i wątek wywołujący ma kontrolę nad zasobem.

Ważne

Podobnie jak w przypadku wszystkich mechanizmów synchronizacji, należy upewnić się, że wszystkie ścieżki kodu czekają na odpowiednim dojściu oczekiwania przed uzyskaniem dostępu do chronionego zasobu. Synchronizacja wątków jest wspólna.

Jeśli zdarzenie automatycznego resetowania jest sygnalizowane, gdy wątki nie czekają, pozostaje zasygnalizowany, dopóki wątek nie będzie czekał na nie. Zdarzenie zwalnia wątek i natychmiast resetuje, blokując kolejne wątki.

Obsługa oczekiwania zdarzeń, które są resetowane ręcznie

Zdarzenie resetowania ręcznego należy utworzyć, określając EventResetMode.ManualReset podczas tworzenia EventWaitHandle obiektu. Jak wskazuje jego nazwa, to zdarzenie synchronizacji musi zostać zresetowane ręcznie po jego zasygnaliczeniu. Dopóki nie zostanie zresetowana, wywołując jej Reset metodę, wątki oczekujące na dojście zdarzeń będą kontynuowane natychmiast bez blokowania.

Zdarzenie resetowania ręcznego działa jak brama corral. Gdy zdarzenie nie jest zasygnalizowane, wątki, które czekają na bloku, jak konie w korze. Gdy zdarzenie jest sygnalizowane, wywołując jego Set metodę, wszystkie wątki oczekujące mogą kontynuować. Zdarzenie pozostaje zasygnaliowane do momentu wywołania jego Reset metody. Dzięki temu zdarzenie resetowania ręcznego jest idealnym sposobem przechowywania wątków, które muszą czekać, aż jeden wątek zakończy zadanie.

Podobnie jak konie opuszczające żrę, potrzeba czasu na zaplanowanie wydanych wątków przez system operacyjny i wznowienie wykonywania. Reset Jeśli metoda jest wywoływana przed wznowieniu wykonywania wszystkich wątków, pozostałe wątki po raz kolejny blokują. Które wątki wznawiają i które wątki bloku zależą od losowych czynników, takich jak obciążenie systemu, liczba wątków oczekujących na harmonogram itd. Nie jest to problem, jeśli wątek, który sygnalizuje zakończenie zdarzenia po sygnalizowaniu, co jest najczęstszym wzorcem użycia. Jeśli chcesz, aby wątek, który zasygnalizował, że zdarzenie rozpocznie nowe zadanie po wznowieniu wszystkich wątków oczekujących, musisz zablokować go do momentu wznowienia wszystkich wątków oczekujących. W przeciwnym razie masz warunek wyścigu, a zachowanie kodu jest nieprzewidywalne.

Funkcje wspólne dla zdarzeń automatycznych i ręcznych

Zazwyczaj co najmniej jeden wątek bloku do EventWaitHandle momentu wywołania odblokowanego wątku Set metody, która zwalnia jeden z oczekujących wątków (w przypadku zdarzeń automatycznego resetowania) lub wszystkich z nich (w przypadku zdarzeń resetowania ręcznego). Wątek może sygnalizować, EventWaitHandle a następnie zablokować na nim, jako operację niepodzielna, wywołując metodę statyczną WaitHandle.SignalAndWait .

EventWaitHandle obiekty mogą być używane ze statycznymi WaitHandle.WaitAll metodami i WaitHandle.WaitAny . EventWaitHandle Ponieważ klasy i Mutex pochodzą z WaitHandleklasy , można użyć obu klas z tymi metodami.

Nazwane zdarzenia

System operacyjny Windows umożliwia obsługę oczekiwania zdarzeń na nazwy. Nazwane zdarzenie ma szeroki zakres systemu. Oznacza to, że po utworzeniu nazwanego zdarzenia jest on widoczny dla wszystkich wątków we wszystkich procesach. W związku z tym zdarzenia nazwane mogą służyć do synchronizowania działań procesów, a także wątków.

Można utworzyć EventWaitHandle obiekt reprezentujący nazwane zdarzenie systemowe przy użyciu jednego z konstruktorów, który określa nazwę zdarzenia.

Uwaga

Ponieważ nazwane zdarzenia są w całym systemie, istnieje możliwość posiadania wielu EventWaitHandle obiektów reprezentujących to samo nazwane zdarzenie. Za każdym razem, gdy wywołujesz konstruktor lub OpenExisting metodę, tworzony jest nowy EventWaitHandle obiekt. Określenie tej samej nazwy wielokrotnie tworzy wiele obiektów reprezentujących to samo nazwane zdarzenie.

Należy zachować ostrożność podczas używania nazwanych zdarzeń. Ponieważ są one szerokie, inny proces, który używa tej samej nazwy, może nieoczekiwanie zablokować wątki. Złośliwy kod wykonywany na tym samym komputerze może użyć go jako podstawy ataku typu "odmowa usługi".

Użyj zabezpieczeń kontroli dostępu, aby chronić EventWaitHandle obiekt reprezentujący nazwane zdarzenie, najlepiej przy użyciu konstruktora, który określa EventWaitHandleSecurity obiekt. Można również zastosować zabezpieczenia kontroli dostępu przy użyciu SetAccessControl metody , ale powoduje to pozostawienie okna luki w zabezpieczeniach między czasem utworzenia uchwytu oczekiwania zdarzeń a czasem jego ochrony. Ochrona zdarzeń za pomocą zabezpieczeń kontroli dostępu pomaga zapobiegać złośliwym atakom, ale nie rozwiązuje problemu nieumyślnych kolizji nazw.

Uwaga

EventWaitHandle W przeciwieństwie do klasy klasy pochodne AutoResetEvent i ManualResetEvent mogą reprezentować tylko lokalne uchwyty oczekiwania. Nie mogą reprezentować nazwanych zdarzeń systemowych.

Zobacz też