4

I have a DLL which has a CWinThread based class called CWork. I create it using AfxBeginThread.

In this class I defined a procedure that will loop infinetly and perform a certain task. This procedure will be used as a thread by itself. I create it also using AfxBeginThread.

Now, when my DLL exits, I'd like to end the thread. This is because I have a crash on exit, and I am affraid that is the reason.

In addition, there is

Pseudo Code example:

class Cmain

Cmain::Cmain(){
    pMyThread = AfxBeginThread(CWork - a CWinThread based Class);
}

 UINT HandleNextVTSConnectionCommandProc(LPVOID pParam);

class CWork

 CWork:CWork(){
   AfxBeginThread(HandleNextVTSConnectionCommandProc, this);
 }


UINT HandleNextVTSConnectionCommandProc(LPVOID pParam){

 while(true){

     dosomething();
     sleep(2000);

 }

}

My question is, what is the correct way of ending those 2 threads?

Thank you!

dushkin
  • 1,939
  • 3
  • 37
  • 82

4 Answers4

5

In general the correct way to end a thread is to ask it to finish and then wait for it to do so. So on Windows you might signal an event to ask the thread to finish up then wait on the thread HANDLE. Forcefully terminating a thread is almost always a misguided idea which will come back to haunt you.

Steve
  • 1,760
  • 10
  • 18
  • Thank you Steve. Is it clever to signal the thread to end when deleteing pMyThread? I mean: to put instead of while(true) - while(flag) and set flag = false in CWork destructor? – dushkin May 26 '15 at 13:10
  • You could do something like that. The advantage of using an Event is that the thread scheduler is on your side. For example, instead of sleeping you'd use WaitForSingleObject with a timeout. This way the thread can respond to the signal while sleeping and no busy wait is required. – Steve May 26 '15 at 13:14
  • Steve, and if I create a thread like this: AfxBeginThread(RUNTIME_CLASS(CMyClass)... How do I end this thread? This is contrary to the first question where I by mistake gave the example of AfxBeginThread with a class as a parameter instead of a proc as it should have been. Thanks. – dushkin May 26 '15 at 15:10
  • 1
    @dushkin: You cannot ever hope to become proficient in MFC without **intimate** knowledge of the Windows API. If you don't know what the `RUNTIME_CLASS` macro does, you're doomed. The answer to your immediate question is simple: You terminate the thread the same way as any other thread. Please do read [Prerequisites for learning MFC programming](http://stackoverflow.com/a/18191454/1889329), you'll be thankful you did. – IInspectable May 26 '15 at 15:19
4

Create an event calling CreateEvent that is initially non-signaled. When your application terminates, signal this event (SetEvent) and wait for the thread to terminate (WaitForSingleObject on the thread handle).

Inside your thread function HandleNextVTSConnectionCommandProc replace your while(true) loop with

while(WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0)

Doing the above allows you to signal the thread to terminate from your application. The thread terminates, when it returns from its thread proc.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
2

Set a flag instead of using while(true) to tell your thread when it should end. You could also use an event.

You should also wait for your thread to be complete before you exit, so you should use (in the main code, once you signal the thread to end):

WaitForSingleObject(thread_handle)
TWA
  • 12,756
  • 13
  • 56
  • 92
1

Something like this should get you started:

HANDLE g_hThreadExitRequest = NULL;

UINT __cdecl ThreadFunction(LPVOID pParam)
{
    AllocConsole();
    HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);

    for (int i=1; true; ++i)
    {
        CStringA count;
        count.Format("%d\n", i);
        WriteFile(hCon, (LPCSTR)count, count.GetLength(), NULL, NULL);

        if (WaitForSingleObject(g_hThreadExitRequest, 1000) == WAIT_OBJECT_0)
            break;
    }

    // We can do any thread specific cleanup here.
    FreeConsole();

    return 0;
}

void Go()
{
    // Create the event we use the request the thread exit.
    g_hThreadExitRequest = CreateEvent(
                                NULL,   // LPSECURITY_ATTRIBUTES lpEventAttributes
                                TRUE,   // BOOL bManualReset
                                FALSE,  // BOOL bInitialState
                                NULL    // LPCTSTR lpName
                                );

    // We create the thread suspended so we can mess with the returned CWinThread without
    // MFC auto deleting it when the thread finishes.
    CWinThread *pThread = AfxBeginThread(
                                &ThreadFunction,        // AFX_THREADPROC pfnThreadProc
                                NULL,                   // LPVOID pParam
                                THREAD_PRIORITY_NORMAL, // int nPriority
                                0,                      // UINT nStackSize
                                CREATE_SUSPENDED ,      // DWORD dwCreateFlags
                                NULL                    // LPSECURITY_ATTRIBUTES lpSecurityAttrs
                                );

    // Turn off MFC's auto delete "feature".
    pThread->m_bAutoDelete = FALSE;

    // Start the thread running.
    pThread->ResumeThread();

    // Wait 30 seconds.
    Sleep(30*1000);

    // Signal the thread to exit and wait for it to do so.
    SetEvent(g_hThreadExitRequest);
    WaitForSingleObject(pThread->m_hThread, INFINITE);

    // Delete the CWinTread object since we turned off auto delete.
    delete pThread;

    // We're finished with the event.
    CloseHandle(g_hThreadExitRequest);
    g_hThreadExitRequest = NULL;
}
Steve
  • 1,760
  • 10
  • 18
  • 1
    my new question was about using a class as aparameter to the AfxBeginThread - AfxBeginThread(RUNTIME_CLASS(CMyClass).... Regarding the AfxBeginThread which takes a thread proc as a parameter - I used your susggestion sucessfully. Thanks. – dushkin May 27 '15 at 06:08