Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to kill a MFC Thread?

I spawn a thread using AfxBeginThread which is just an infinite while loop:

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

How do I kill off this thread in my class destructor?

I think something like

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

and then set m_bKillThread to FALSE in the destructor. But I still need to wait in the destructor until the thread is dead.

like image 950
Nick Avatar asked Feb 26 '09 14:02

Nick


3 Answers

First you have to start the thread in a way so MFC doesn't delete the thread object when it's finished, the default setting for MFC thread is to delete itself so you want to turn that off.

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

Now in the thread, you want a mechanism that the caller thread can send it a signal to end itself. There are multiple ways, one is the WaitForSingleObject to check the status of the signal or another way is to simply send this thread a message to end itself. This is graceful ending rather killing it.

While this thread is ending itself (= exiting the thread function, cleaning up), you can have the main thread wait on it to finish before it exits.

     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;
     }

Note setting m_bAutoDelete = FALSE above made it possible we still have a valid handle when thread finishes so we can wait on it. The last thing you want to do now is delete the CWinThread object to free its memory (since we took the responsibility to do that).

like image 82
zar Avatar answered Sep 27 '22 18:09

zar


Actively killing the thread:

Use the return value of AfxBeginThread (CWinThread*) to get the thread handle (m_hThread) then pass that handle to the TerminateThread Win32 API. This is not a safe way to terminate threads though, so please read on.

Waiting for the thread to finish:

Use the return value of AfxBeginThread (CWinThread*) to get the member m_hThread, then use WaitForSingleObject(p->m_hThread, INFINITE); If this function returns WAIT_OBJECT_0, then the thread is finished. Instead of INFINITE you could also put the number of milliseconds to wait before a timeout happens. In this case WAIT_TIMEOUT will be returned.

Signaling to your thread that it should end:

Before doing the WaitForSingleObject just set some kind of flag that the thread should exit. Then in your main loop of the thread you would check for that bool value and break the infinite loop. In your destructor you would set this flag then do a WaitForSingleObject.

Even better ways:

If you need even more control you can use something like boost conditions.

like image 19
Brian R. Bondy Avatar answered Nov 17 '22 06:11

Brian R. Bondy


BTW, About TerminateThread(), use it this way.

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;
}
like image 6
plan9assembler Avatar answered Nov 17 '22 05:11

plan9assembler