2009-10-26 20 views
5

Jestem naprawdę zakłopotany, aby zadać tak trywialne pytanie, ale debugowanie niektórych programów przekonało mnie teraz, że tak naprawdę nie rozumiem tego problemu:Zdarzenia asynchroniczne i .NET?

Jak działają zdarzenia .NET z wysokości 20 000 stóp? Nie mam na myśli wzorca obsługi delegata/zdarzenia i tego wszystkiego. Mam na myśli to - co jest DUŻYM obrazkiem:

  1. Kod A coś robi.
  2. Występuje pewien zewnętrzny wyzwalacz. Załóżmy na przykład, że użytkownik kliknął jakiś element sterujący.
  3. Magia się dzieje i wywoływana jest obsługa zdarzeń dla zdarzenia.
  4. Kolejna magia się dzieje po powrocie obsługi zdarzeń.

Co to jest magia? Jak to się ma do wątków? Czy wątek z uruchomionym kodem zostanie przerwany po wystąpieniu zdarzenia, a następnie wznawiany po powrocie programu obsługi zdarzeń? Ale ja googled i found out, że. Handlery .NET są nazywane synchronicznie w oryginalnym wątku. Więc kto zajmuje się zatrzymaniem i wznowieniem kodu A? Co się dzieje, gdy zdarzenia są zagnieżdżone (np. Zdarzenie 2 ma miejsce, gdy uruchomiona jest procedura obsługi zdarzeń dla zdarzenia 1)?

Edit: O ile mi zrozumieć odpowiedzi powiedzieć, że obsługi zdarzeń dla następnego imprezy będzie działać dopiero po zakończeniu aktualnie uruchomione obsługi zdarzeń. Oznacza to, że twój kod nie zostanie przerwany: linia n zawsze będzie działała natychmiast po linii n-1 i tuż przed linią n + 1. Jednak zanim opublikowałem pytanie, debugowałem program sterujący za pomocą automatyzacji programem Internet Explorer (przy użyciu SWExplorerAutomation z Webius). Jestem całkiem pewien, że kiedy przechodziłem linię kodu, zostałem "porwany" :-) do jakiejś obsługi zdarzenia i wróciłem do przerwanej pozycji w kodzie, gdy ten program obsługi zdarzeń zakończył swoją działalność. Oznacza to, że albo nie rozumiem odpowiedzi, albo że program zachowuje się inaczej, gdy przechodzi przez debugger!

Odpowiedz

3

Pozwól mi rzucić trochę światła na twój problem. Magia jest pętlą wiadomości systemu Windows. Widzisz w swoim przykładzie, właściwie nic nie stoi na przeszkodzie, aby kod A zatrzymał się, gdy wystąpi zdarzenie. Jest to raczej kolejność.

Gdy kod A jest uruchomiony, użytkownik klika przycisk. Komunikat okna przycisku zostanie umieszczony w kolejce, ale nic się nie dzieje. Gdy kod A wyjdzie z funkcji lub zrezygnuje z kontroli do pętli komunikatów, wówczas przetwarzane jest zdarzenie Click i uruchamiana jest obsługa zdarzeń.

Spróbuj tego eksperymentu. Umieść pętlę nieskończoności wewnątrz programu w głównym wątku, a następnie kliknij interfejs użytkownika. Zauważysz, że interfejs użytkownika przestanie odpowiadać i nie będzie działał żaden moduł obsługi zdarzeń.

+0

Dotyczy to aplikacji WinForm, ale nie należy zapominać o bardziej ogólnym przypadku, w którym nie ma włączonej pompy komunikatów. W tym przypadku wszystko przebiega synchronicznie bez mitigatora i nie ma w tym magii. – bzlm

+0

@bzim Rozumiem stare dobre mulit-mailboxes, model "przebudź-kiedy-wiadomość-przyjeżdża-jeśli-jestem-o-wyższym priorytecie niż-obecnie-działający-zadanie tak jak w starym dobrym RMXie Intela. To, czego nie rozumiem, to sztuczka systemu Windows. – Avi

2

rzeczą, którą zobaczy z 20.000 stóp jest MessageLoop. Jest w środku Application.Run().

Krótko mówiąc, jest to podczas pętli, która biegnie przez całą żywotność aplikacji i robi

// pseudo code, I did not reflector Application.Run 
    while (GetMessage(ref msg) 
    { 
    DispatchMessage(ref msg); 
    } 

Można zauważyć simgle gwintem gdy trwa zbyt długo obchodzenie 1 wydarzenie, aplikacja będzie o nazwie "brak reakcji" w TaskManager.

Podobna metoda to Application.DoEvents(), ale trzymaj się z dala od tego.

+0

Dotyczy to aplikacji WinForm, ale nie należy zapominać o bardziej ogólnym przypadku, w którym nie ma włączonej pompy komunikatów. W tym przypadku wszystko przebiega synchronicznie bez mitigatora i nie ma w tym magii. – bzlm

+0

bzim, zareagowałem na przykład kliknięcia Control. Masz rację ogólnie, ale myślę, że OP myśli o WinFormach. –

1

Zdarzenia są wskaźnikami funkcji (podobnie jak w C++). Kiedy używasz zwykłego wanilowego zdarzenia .NET, w rzeczywistości wywołujesz funkcje, które są połączone za pomocą + = z tym wydarzeniem. Tak więc od 20 000 stóp twój kod wywołuje inny kod, tak jak wywołanie innej funkcji. To dlatego nazywa się synchronicznie i w tym samym wątku.

Wewnątrz kontroli WinForm/WPF mamy również pętlę wiadomości do rozważenia: Wszystkie zdarzenia, które występują w kontekście formularza, dodają komunikat do pętli wiadomości zamiast wywoływania metody bezpośrednio.

Główny wątek sondowania pętli dla nowych wiadomości i kiedy pojawia się nowa wiadomość, on wykonuje ją (ponownie w głównym wątku) tylko teraz nie jest dokładnie synchroniczny.

Jest to spowodowane tym, że jeśli formularz jest zajęty robieniem czegoś i naciśnięciem przycisku, naciśnięcie tego przycisku zajmuje trochę czasu. jest to również powód, dla którego, jeśli unieważnisz formant, jego wygląd zostanie zmieniony tylko po wyjściu z działającej metody (i przetwarzana jest następna wiadomość).

+0

0. Dziękuję za odpowiedź :-) 1. Czy mówisz, że KAŻDE sterowanie (przycisk, etykieta, lista-listy itp.) W formularzu ma własną pętlę komunikatów i własny wątek? A każda kontrolka HTML na stronie internetowej? Wydaje się to naprawdę marnotrawstwem. 2. Nie zrozumiałem całej sekcji zaczynającej się od "To jest powód ...". Czy możesz wytłumaczyć? – Avi

+0

1. Jeśli dobrze pamiętam Każde główne okno ma swoją własną pętlę komunikatów - nie każda kontrolka 2. Pętla komunikatów jest przyczyną, że wywołania w tym samym wątku nie są synchroniczne - np. Naciśnięcie przycisku nie powoduje naciśnięcia przycisku pośrednio, ale działa w kontekście głównego wątku. –

+0

Dror, nie każde okno, każda aplikacja. I chociaż możesz zacząć drugi, który jest bardzo rzadki. –

Powiązane problemy