TerminateThread to zły pomysł, zwłaszcza jeśli twój wątek korzysta z obiektów synchronizacji, takich jak muteksy. Może to prowadzić do niewydanej pamięci i uchwytów oraz do zakleszczeń, więc masz rację, że musisz zrobić coś innego.
Zazwyczaj sposobem zakończenia wątku jest powrót z funkcji definiującej wątek. Główny wątek sygnalizuje wątek roboczy do wyjścia przy użyciu obiektu zdarzenia lub nawet prostej wartości boolowskiej, jeśli jest ona często sprawdzana. Jeśli wątek roboczy czeka z numerem WaitForSingleObject
, być może trzeba go zmienić na WaitForMultipleObjects
, gdzie jednym z obiektów jest zdarzenie. Główny wątek zadzwoniłby pod numer SetEvent
, a wątek roboczy zostałby przebudzony i powrócił.
Naprawdę nie możemy podać żadnego użytecznego kodu, chyba że pokażesz nam, co robisz. W zależności od tego, co robi wątek roboczy i jak główny wątek przekazuje mu informacje, może wyglądać zupełnie inaczej.
Ponadto, w [teraz bardzo stary] MSVC, należy użyć _beginthreadex
zamiast CreateThread
w celu uniknięcia wycieków pamięci w CRT. Zobacz MSKB #104641.
Aktualizacja:
Jednym z zastosowań wątku roboczego jest jako „Timer”, aby zrobić kilka operacji na regularnych odstępach czasu. Najprostszy:
for (;;) {
switch (WaitForSingleObject(kill_event, timeout)) {
case WAIT_TIMEOUT: /*do timer action*/ break;
default: return 0; /* exit the thread */
}
}
Innym zastosowaniem jest zrobienie czegoś na żądanie. Zasadniczo to samo, ale z limitem czasu ustawionym na INFINITE
i wykonaniem jakiegoś działania na WAIT_OBJECT_0
zamiast na WAIT_TIMEOUT
. W tym przypadku potrzebne są dwa zdarzenia, jeden, aby obudzić wątek się i zrobić jakąś akcję, kolejny, aby obudzić i wyjść:
HANDLE handles[2] = { action_handle, quit_handle };
for (;;) {
switch (WaitForMultipleObject(handles, 2, FALSE, INFINITE)) {
case WAIT_OBJECT_0 + 0: /* do action */ break;
default:
case WAIT_OBJECT_0 + 1: /* quit */ break;
}
}
Należy pamiętać, że ważne jest, że pętla zrobić coś rozsądnego jeśli WFSO/WFMO zwraca błąd zamiast jednego z oczekiwanych wyników. W obu powyższych przykładach po prostu traktujemy błąd tak, jakbyśmy byli sygnalizowani, aby zakończyć.
Możesz osiągnąć ten sam wynik w pierwszym przykładzie, zamykając uchwyt zdarzenia z głównego wątku, powodując błąd wątku roboczego od WaitForSingleObject
i kończąc, ale nie poleciłbym tego podejścia.
Funkcja wywołania zwrotnego wątku jest dla (;;) to wszystko. nic niezwykłego. tak, powtórzę pytanie, używając WaitForSingleObject() i SetEvent() w jaki sposób mogę zasygnalizować mój wątek, który muszę dokończyć? Jeśli zadzwonię do SetEvet (FinishEvent), to co zwróci WaitForSingleObject()? 0? 1? -1? – Uri
@Uri Po wywołaniu 'SetEvent',' WaitForSingleObject' zwróci 'WAIT_OBJECT_0' (co oznacza 0). Kiedy wspomniałeś o używaniu 'WaitForSingleObject', założyłem, że oznacza to, że już korzystałeś z tego zdarzenia, aby zasygnalizować wątek roboczy, aby coś zrobił (poza wyjściem).Zwróć też uwagę, że w niektórych przypadkach musisz sygnalizować wątek wotker, aby wyjść, a następnie poczekać, aż faktycznie się zatrzyma, zanim przejdziesz dalej. (W tym celu możesz użyć 'WaitForSingleObject' na uchwycie nici). –
+1 Oto odpowiedź, którą dałbym. Czy to w ten sposób wiele razy. –