2009-02-26 9 views
10

I tarło wątku przy użyciu AfxBeginThread która jest po prostu nieskończona pętla:Jak zabić wątek MFC?

UINT CMyClass::ThreadProc(LPVOID param) 
{ 
    while (TRUE) 
    { 
     // do stuff 
    } 
    return 1; 
} 

Jak mogę zabić ten wątek w mojej klasie destructor?

myślę coś

UINT CMyClass::ThreadProc(LPVOID param) 
{ 
    while (m_bKillThread) 
    { 
     // do stuff 
    } 
    return 1; 
} 

a następnie ustawić m_bKillThread do FALSE w destructor. Ale nadal muszę czekać w destruktorze, aż wątek będzie martwy.

Odpowiedz

19

Aktywne zabijania nici:

pomocą wartość powrotną AfxBeginThread (CWinThread*), aby uzyskać uchwyt wątku (m_hThread), a następnie przechodzą, że uchwyt API TerminateThread Win32. Nie jest to jednak bezpieczny sposób na przerwanie wątków, więc czytaj dalej.

Oczekiwanie na wątku do końca:

Zastosowanie wartość zwracana AfxBeginThread (CWinThread*), aby uzyskać element m_hThread, a następnie użyć WaitForSingleObject(p->m_hThread, INFINITE); Jeśli ta funkcja zwraca WAIT_OBJECT_0, wówczas gwint jest zakończona. Zamiast INFINITE możesz również ustawić liczbę milisekund do oczekiwania przed upływem limitu czasu. W takim przypadku zostanie zwrócone WAIT_TIMEOUT.

sygnalizacyjne do wątku, który powinien Koniec:

Przed wykonaniem WaitForSingleObject Wystarczy ustawić jakąś flagę, że wątek powinien wyjść. Następnie w głównej pętli wątku sprawdzasz tę wartość bool i przerywasz nieskończoną pętlę. W swoim destruktorze ustawisz tę flagę, a następnie wykonaj WaitForSingleObject.

Nawet lepsze sposoby:

Jeśli potrzebujesz jeszcze większą kontrolę można użyć coś jak boost conditions.

1

Musisz poczekać, aż wątek zrobi wszystko.

if(WaitForSingleObject(thread_handle, INFINITE) == WAIT_OBJECT_0) 
    ;//all right 
else 
    ;//report error 

uwaga przy użyciu funkcji TerminateThread, jest to bardzo niebezpieczne.

4

BTW, o TerminateThread(), użyj go w ten sposób.

DWORD exit_code= NULL; 
if (thread != NULL) 
{ 
    GetExitCodeThread(thread->m_hThread, &exit_code); 
    if(exit_code == STILL_ACTIVE) 
    { 
     ::TerminateThread(thread->m_hThread, 0); 
     CloseHandle(thread->m_hThread); 
    } 
    thread->m_hThread = NULL; 
    thread = NULL; 
} 
1

Najpierw trzeba uruchomić wątku w taki sposób, MFC nie usunąć obiekt wątek, kiedy to finished, domyślne ustawienie dla MFC wątku jest usunąć się tak chcesz to wyłączyć.

m_thread = AfxBeginThread(ThreadProc, this, THREAD_PRIORITY_NORMAL ,CREATE_SUSPENDED); 
    m_thread->m_bAutoDelete = FALSE; 
    m_thread->ResumeThread(); 

Teraz w wątku, chcesz mechanizm, który wątek wywołujący może wysłać sygnał do samego końca. Istnieje wiele sposobów, jeden jest WaitForSingleObject, aby sprawdzić status sygnału lub w inny sposób jest po prostu wysłać ten wątek wiadomość, aby się zakończyć. To jest pełne wdzięku zakończenie, a raczej zabicie go.

Podczas gdy ten wątek się kończy (= wyjście z funkcji wątku, czyszczenie), możesz poczekać, aż główny wątek się zakończy, zanim zakończy działanie.

 int wait = 2000 // seconds (I am waiting for 2 seconds for worker to finish) 
    int dwRes = WaitForSingleObject(m_thread->m_hThread, wait); 
    switch (dwRes) 
    { 
    case WAIT_OBJECT_0: 
     TRACE(_T("worker thread just finished")); break; 
    case WAIT_TIMEOUT: 
     TRACE(_T("timed out, worker thread is still busy")); break; 
    } 

ustawienie Uwaga m_bAutoDelete = FALSE powyżej pozwoliły wciąż mamy poprawny uchwyt gdy wątek zakończy więc możemy czekać na niego. Ostatnią rzeczą, którą chcesz teraz zrobić, jest usunięcie obiektu CWinThread w celu zwolnienia jego pamięci (ponieważ wzięliśmy na siebie odpowiedzialność za to).