Win32,MFC:结束线程

4
我有一个DLL,其中包含一个名为CWork的基于CWinThread的类。我使用AfxBeginThread创建它。
在这个类中,我定义了一个无限循环并执行某个任务的过程。这个过程将作为一个线程被单独使用。我也使用AfxBeginThread创建它。
现在,当我的DLL退出时,我想结束这个线程。这是因为我在退出时遇到了崩溃,并且我担心这就是原因。
另外还有伪代码示例:
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);

 }

}

我的问题是,结束这两个线程的正确方法是什么?

谢谢!

4个回答

5

一般来说,正确的结束线程的方式是请求它完成,然后等待它完成。因此,在Windows上,您可以发出一个信号事件来要求线程完成,然后等待线程句柄。强制终止线程几乎总是一个错误的想法,这将会给你带来麻烦。


谢谢Steve。在删除pMyThread时,向线程发出结束信号是否聪明?我的意思是:在CWork析构函数中将while(true)替换为while(flag),并设置flag = false? - dushkin
你可以这样做。使用事件的优点是线程调度器在你这边。例如,你可以使用带有超时的 WaitForSingleObject 而不是睡眠。这样线程可以在睡眠时响应信号,而无需忙等待。 - Steve
Steve,如果我像这样创建一个线程:AfxBeginThread(RUNTIME_CLASS(CMyClass)...),我该如何结束这个线程?这与第一个问题相反,那里我错误地给出了一个带有类参数的AfxBeginThread示例,而不是应该是一个proc。谢谢。 - dushkin
1
@dushkin:如果你不对Windows API有深入的了解,就不可能成为MFC的专家。如果你不知道RUNTIME_CLASS宏的作用,那么你注定会失败。对于你的直接问题,答案很简单:你可以像终止其他线程一样终止该线程。请务必阅读学习MFC编程的先决条件,你会感激自己这样做的。 - IInspectable

4
创建一个名为CreateEvent的事件,初始状态为未发信号。当应用程序终止时,发出此事件(SetEvent),并等待线程终止(在线程句柄上使用WaitForSingleObject)。
在您的线程函数HandleNextVTSConnectionCommandProc中,将while(true)循环替换为
while(WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0)

通过上述方法,您可以从应用程序中向线程发送终止信号。当线程从其线程过程返回时,线程将终止。


2

使用标志位来告诉线程何时结束,而不是使用while(true)。你也可以使用事件。

在退出之前,应等待线程完成,因此应该在主代码中使用以下方法(一旦发出线程结束信号):

WaitForSingleObject(thread_handle)

1
像这样的东西应该能帮你入门:
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;
}

1
我的新问题是关于将类作为参数传递给AfxBeginThread函数 - AfxBeginThread(RUNTIME_CLASS(CMyClass).... 关于以线程过程为参数的AfxBeginThread - 我成功地使用了您的建议。谢谢。 - dushkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接