Nigdy wcześniej nie korzystałem z wątków w C #, w których muszę mieć dwa wątki, a także główny wątek interfejsu użytkownika. Zasadniczo mam następujące.
public void StartTheActions()
{
//Starting thread 1....
Thread t1 = new Thread(new ThreadStart(action1));
t1.Start();
// Now, I want for the main thread (which is calling `StartTheActions` method)
// to wait for `t1` to finish. I've created an event in `action1` for this.
// The I wish `t2` to start...
Thread t2 = new Thread(new ThreadStart(action2));
t2.Start();
}
Zasadniczo moje pytanie brzmi: jak sprawić, by wątek czekał na zakończenie innego. Jaki jest najlepszy sposób, aby to zrobić?
c#
multithreading
Maxim Zaslavsky
źródło
źródło
Odpowiedzi:
Widzę 5 dostępnych opcji:
1. Thread.Join
Jak w przypadku odpowiedzi Mitcha. Ale to zablokuje twój wątek interfejsu użytkownika, jednak otrzymasz wbudowany limit czasu.
2. Użyj
WaitHandle
ManualResetEvent
jestWaitHandle
jak sugerowała jrista.Należy zwrócić uwagę na to, że jeśli chcesz czekać na wiele wątków,
WaitHandle.WaitAll()
nie będzie działać domyślnie, ponieważ wymaga wątku MTA. Możesz to obejść, oznaczając swojąMain()
metodę znakiemMTAThread
- jednak blokuje to twoją pompę wiadomości i nie jest zalecane z tego, co przeczytałem.3. Odpal wydarzenie
Zobacz tę stronę Jon Skeet o wydarzeniach i wielowątkowości, to możliwe, że zdarzenie może stać unsubcribed pomiędzy
if
iEventName(this,EventArgs.Empty)
- zdarzyło mi się to wcześniej.(Mam nadzieję, że te kompilacje, nie próbowałem)
4. Użyj pełnomocnika
Jeśli używasz metody _count, może być pomysłem (ze względów bezpieczeństwa), aby ją zwiększyć za pomocą
Interlocked.Increment(ref _count)
Chciałbym poznać różnicę między używaniem delegatów a zdarzeniami do powiadamiania o wątkach, jedyną różnicą, jaką znam, jest to, że zdarzenia są wywoływane synchronicznie.
5. Zrób to asynchronicznie
Odpowiedź na to pytanie zawiera bardzo jasny opis możliwości tej metody.
Deleguj / Zdarzenia w niewłaściwym wątku
Sposób działania zdarzenia / delegata będzie oznaczał, że metoda obsługi zdarzeń znajduje się w wątku1 / wątku2, a nie w głównym wątku interfejsu użytkownika , więc będziesz musiał przełączyć się z powrotem na górę metod HandleThreadDone:
źródło
Dodaj
po uruchomieniu, ale to nie da wiele, ponieważ jest to zasadniczo taki sam wynik, jak uruchomienie w głównym wątku!
Mogę gorąco polecić przeczytanie darmowego e-booka Joe Albahari's Threading in C # , jeśli chcesz poznać wątki w .NET.
źródło
Join
wydaje się, że pytający dosłownie o to prosił, może to być ogólnie bardzo złe. Wezwanie doJoin
rozłączy wątek, z którego to się dzieje. Jeśli to jest główny wątek GUI, to jest ZŁE ! Jako użytkownik aktywnie nienawidzę aplikacji, które wydają się działać w ten sposób. Zobacz więc wszystkie inne odpowiedzi na to pytanie i stackoverflow.com/questions/1221374/ ...Poprzednie dwie odpowiedzi są świetne i sprawdzą się w prostych scenariuszach. Istnieją jednak inne sposoby synchronizowania wątków. Poniższe również będą działać:
ManualResetEvent jest jednym z wielu WaitHandle , które ma do zaoferowania platforma .NET. Mogą zapewnić znacznie bogatsze możliwości synchronizacji wątków niż proste, ale bardzo popularne narzędzia, takie jak lock () / Monitor, Thread.Join itp. Mogą być również używane do synchronizowania więcej niż dwóch wątków, umożliwiając złożone scenariusze, takie jak wątek „główny” który koordynuje wiele wątków `` potomnych '', wiele współbieżnych procesów, które są zależne od kilku etapów wzajemnej synchronizacji itp.
źródło
W przypadku korzystania z platformy .NET 4 ten przykład może pomóc:
z: https://stackoverflow.com/a/4190969/1676736
źródło
Chcesz
Thread.Join()
metody lub jednego z jej przeciążeń .źródło
Chciałbym, aby twój główny wątek przekazał metodę wywołania zwrotnego do twojego pierwszego wątku, a kiedy to się skończy, wywoła metodę wywołania zwrotnego na głównym wątku, który może uruchomić drugi wątek. Dzięki temu główny wątek nie zwisa podczas oczekiwania na połączenie lub Waithandle. Przekazywanie metod jako delegatów jest i tak przydatna do nauczenia się w języku C #.
źródło
Spróbuj tego:
źródło
Wysyłając, aby być może pomóc innym, spędziłem trochę czasu na poszukiwaniu rozwiązania takiego jak to, co wymyśliłem. Więc przyjąłem trochę inne podejście. Powyżej znajduje się opcja licznika, po prostu zastosowałem ją nieco inaczej. Odpędzałem wiele wątków, zwiększałem licznik i zmniejszałem licznik, gdy wątek zaczynał się i kończył. Następnie w głównej metodzie chciałem wstrzymać i poczekać na zakończenie wątków.
Udokumentowane na moim blogu. http://www.adamthings.com/post/2012/07/11/ensure-threads-have-finished-before-method-continues-in-c/
źródło
Kiedy chcę, aby interfejs użytkownika mógł aktualizować swój wyświetlacz podczas oczekiwania na zakończenie zadania, używam pętli while, która testuje IsAlive w wątku:
źródło
Oto prosty przykład, który czeka na zakończenie bieżnika w tej samej klasie. Wykonuje również wywołanie innej klasy w tej samej przestrzeni nazw. Dołączyłem instrukcje „using”, aby mógł być wykonywany jako Winform tak długo, jak długo tworzysz button1.
źródło