Przeczytałem dokumentację na ten temat i myślę, że rozumiem. An AutoResetEvent
resetuje się, gdy przechodzi przez kod event.WaitOne()
, ale ManualResetEvent
nie.
Czy to jest poprawne?
c#
.net
multithreading
autoresetevent
manualresetevent
Ben McNiel
źródło
źródło
Odpowiedzi:
Tak. To jak różnica między bramką a drzwiami. Są
ManualResetEvent
to drzwi, które należy zamknąć (zresetować) ręcznie. JestAutoResetEvent
to punkt poboru opłat, umożliwiający przejazd jednego samochodu i automatyczne zamykanie się przed przejściem następnego.źródło
Wystarczy wyobrazić sobie, że
AutoResetEvent
sporządziWaitOne()
iReset()
jako jednej operacji atomowej.źródło
Krótka odpowiedź brzmi: tak. Najważniejszą różnicą jest to, że AutoResetEvent pozwoli na kontynuację tylko jednego wątku oczekującego. Z drugiej strony ManualResetEvent będzie nadal pozwalał na kontynuowanie wątków, nawet kilku w tym samym czasie, dopóki nie powiesz, aby przestał (Zresetuj).
źródło
Wątki w C # - bezpłatny e-book
ManualResetEvent to odmiana AutoResetEvent. Różni się tym, że nie resetuje się automatycznie po przepuszczeniu wątku w wywołaniu WaitOne, a więc działa jak brama: wywołanie Set otwiera bramę, umożliwiając dowolną liczbę wątków, przez które przechodzi WaitOne; wywołanie Reset zamyka bramę, potencjalnie powodując, że kolejka kelnerów gromadzi się aż do jej następnego otwarcia.
Można symulować tę funkcjonalność za pomocą logicznego pola „gateOpen” (zadeklarowanego zmiennym słowem kluczowym) w połączeniu z „spin-sleep” - wielokrotnie sprawdzając flagę, a następnie śpiąc przez krótki czas.
ManualResetEvents są czasami używane do sygnalizowania, że dana operacja została zakończona lub że inicjalizacja wątku jest gotowa do wykonania pracy.
źródło
Stworzyłem proste przykłady, aby wyjaśnić zrozumienie
ManualResetEvent
vsAutoResetEvent
.AutoResetEvent
: załóżmy, że masz 3 wątki pracowników. Jeśli którykolwiek z tych wątków wywołaWaitOne()
wszystkie pozostałe 2 wątki zatrzymają wykonywanie i będą czekać na sygnał. Zakładam, że używająWaitOne()
. To jest jak; jeśli nie pracuję, nikt nie działa. W pierwszym przykładzie możesz to zobaczyćKiedy zadzwonisz,
Set()
wszystkie wątki będą działać i będą czekać na sygnał. Po 1 sekundzie wysyłam drugi sygnał, a one wykonują polecenie i czekają (WaitOne()
). Pomyśl o tych facetach, którzy grają w drużyny piłkarskie, a jeśli jeden z graczy powie, że poczekam, aż menedżer do mnie zadzwoni, a inni poczekają, aż menedżer powie im, aby kontynuowali (Set()
)W tym przykładzie widać wyraźnie, że po pierwszym uderzeniu
Set()
puści wszystkie wątki, a po 1 sekundzie sygnalizuje wszystkim wątkom, że muszą czekać! Gdy tylko ustawisz je ponownie, niezależnie od tego, czy dzwonią wWaitOne()
środku, będą one działać, ponieważ musisz ręcznie dzwonićReset()
aby zatrzymać je wszystkie.Chodzi raczej o relację sędziów / zawodników tam, niezależnie od tego, który z zawodników jest kontuzjowany i czeka na grę inni będą kontynuować pracę. Jeśli Sędzia mówi czekaj (
Reset()
), wszyscy gracze będą czekać do następnego sygnału.źródło
autoResetEvent.WaitOne()
jest podobne do
jako operacja atomowa
źródło
OK, zwykle nie jest dobrą praktyką dodawanie 2 odpowiedzi w tym samym wątku, ale nie chciałem edytować / usuwać mojej poprzedniej odpowiedzi, ponieważ może to pomóc w inny sposób.
Teraz stworzyłem, o wiele bardziej wszechstronny i łatwy do zrozumienia, fragment aplikacji konsoli do uruchomienia poniżej.
Po prostu uruchom przykłady na dwóch różnych konsolach i obserwuj zachowanie. Dowiesz się o wiele wyraźniej, co dzieje się za kulisami.
Zdarzenie resetowania ręcznego
Zdarzenie automatycznego resetu
źródło
AutoResetEvent utrzymuje w pamięci zmienną boolowską. Jeśli zmienna boolowska ma wartość false, wówczas blokuje wątek, a jeśli zmienna boolowska ma wartość true, odblokowuje wątek.
Kiedy tworzymy instancję obiektu AutoResetEvent, przekazujemy domyślną wartość wartości boolowskiej do konstruktora. Poniżej znajduje się składnia wystąpienia obiektu AutoResetEvent.
Metoda WaitOne
Ta metoda blokuje bieżący wątek i czeka na sygnał innego wątku. Metoda WaitOne ustawia bieżący wątek w stan wątku uśpienia. Metoda WaitOne zwraca true, jeśli odbiera sygnał, w przeciwnym razie zwraca false.
Drugie przeciążenie metody WaitOne odczekaj określoną liczbę sekund. Jeśli nic nie otrzyma, wątek kontynuuje pracę.
Wywołaliśmy metodę WaitOne, przekazując 2 sekundy jako argumenty. W pętli while czeka na sygnał przez 2 sekundy, a następnie kontynuuje pracę. Gdy wątek otrzyma sygnał, WaitOne zwraca wartość true, wychodzi z pętli i drukuje komunikat „Wątek dostał sygnał”.
Ustaw metodę
Metoda AutoResetEvent Set wysłała sygnał do oczekującego wątku, aby kontynuować pracę. Poniżej znajduje się składnia wywołania metody Set.
ManualResetEvent utrzymuje w pamięci zmienną boolowską. Gdy zmienna boolowska ma wartość false, wówczas blokuje wszystkie wątki, a gdy zmienna boolowska ma wartość true, odblokowuje wszystkie wątki.
Kiedy tworzymy instancję ManualResetEvent, inicjalizujemy ją z domyślną wartością logiczną.
W powyższym kodzie inicjujemy ManualResetEvent wartością false, co oznacza, że wszystkie wątki wywołujące metodę WaitOne będą blokowane, dopóki niektóre wątki nie wywołają metody Set ().
Jeśli zainicjujemy ManualResetEvent z wartością true, wszystkie wątki wywołujące metodę WaitOne nie będą blokować i będą mogły kontynuować.
Metoda WaitOne
Ta metoda blokuje bieżący wątek i czeka na sygnał innego wątku. Zwraca true, jeśli odbiera sygnał, w przeciwnym razie false.
Poniżej znajduje się składnia wywołania metody WaitOne.
W drugim przeciążeniu metody WaitOne możemy określić przedział czasu do momentu, aż bieżący wątek będzie czekać na sygnał. Jeśli w czasie wewnętrznym, nie odbiera sygnału, zwraca false i przechodzi do następnej linii metody.
Poniżej znajduje się składnia wywołania metody WaitOne z interwałem czasowym.
Określiliśmy 5 sekund na metodę WaitOne. Jeśli obiekt manualResetEvent nie odbiera sygnału przez 5 sekund, ustawia zmienną isSignalled na false.
Ustaw metodę
Ta metoda służy do wysyłania sygnału do wszystkich oczekujących wątków. Metoda Set () ustaw zmienną boolean obiektu ManualResetEvent na wartość true. Wszystkie oczekujące wątki są odblokowane i idą dalej.
Poniżej znajduje się składnia wywołania metody Set ().
Metoda resetowania
Po wywołaniu metody Set () na obiekcie ManualResetEvent jej wartość logiczna pozostaje prawdziwa. Aby zresetować wartość, możemy użyć metody Reset (). Metoda resetowania zmienia wartość logiczną na false.
Poniżej znajduje się składnia wywołania metody Reset.
Musimy natychmiast wywołać metodę Reset po wywołaniu metody Set, jeśli chcemy wielokrotnie wysyłać sygnał do wątków.
źródło
Tak. To jest absolutnie poprawne.
Możesz zobaczyć ManualResetEvent jako sposób na wskazanie stanu. Coś jest włączone (Ustaw) lub wyłączone (Zresetuj). Wystąpienie o pewnym czasie trwania. Każdy wątek oczekujący na taki stan może być kontynuowany.
AutoResetEvent jest bardziej porównywalny do sygnału. Jeden strzał wskazujący, że coś się stało. Wystąpienie bez żadnego czasu trwania. Zazwyczaj, choć niekoniecznie, „coś”, co się wydarzyło, jest małe i musi być obsługiwane przez pojedynczy wątek - stąd automatyczne resetowanie po zużyciu zdarzenia przez pojedynczy wątek.
źródło
Tak to prawda.
Możesz uzyskać pomysł, korzystając z tych dwóch.
Jeśli chcesz powiedzieć, że skończyłeś trochę pracy i inne (wątki), które na to czekają, mogą teraz kontynuować, powinieneś użyć ManualResetEvent.
Jeśli potrzebujesz wzajemnego wyłącznego dostępu do dowolnego zasobu, powinieneś użyć AutoResetEvent.
źródło
Jeśli chcesz zrozumieć AutoResetEvent i ManualResetEvent, musisz zrozumieć, że nie ma wątków, ale przeszkadza!
.NET chce wyczarować programowanie niskiego poziomu jak najdalej.
Przerwania są czymś używanym w programowaniu niskiego poziomu, co jest równoznaczne z sygnałem, który z niskiego stał się wysoki (lub odwrotnie). Kiedy tak się dzieje, program przerywa normalne wykonywanie i przesuwa wskaźnik wykonania do funkcji, która obsługuje to zdarzenie .
Pierwszą rzeczą do zrobienia po wystąpieniu przerwania jest zresetowanie jego stanu, ponieważ sprzęt działa w ten sposób:
Jest to różnica między ManualResetEvent i AutoResetEvent.
Jeśli zdarzy się ManualResetEvent i nie zresetuję go, następnym razem nie będzie w stanie go słuchać.
źródło