安全终止MFC线程

匿名 (未验证) 提交于 2019-12-03 00:22:01












下一个方法是另外保存线程的句柄。在线程创建后,将m_hThread保存在另一个变量中,以后访问这个变量就是了。但是要小心,在复制句柄以前线程并没有结束,最安全的方法是在AfxBeginThread中传入CREATE_SUSPENDED,保存句柄,然后通过调用ResumeThread,重新开始线程。这两种方法都可以帮助用户得到CWinThread对象的返回代码。

对于Worker线程,终止线程可以使用线程的退出码作为返回值从线程函数返回。

对于UI线程,因为有消息循环,需要发送一个WM_QUIT消息到线程的消息队列,当线程接收到WM_QUIT消息时退出消息循环。因此,结束线程可以在线程内部调用SDK的PostQuitMessage函数,发送WM_QUIT消息。
PostQuitMessage函数的定义如下:

void PostQuitMessage(int nExitCode);

其中:

nExitCode:线程的退出码。

MFC还提供了AfxEndThread函数,Worker线程和UI线程都可以通过在线程内部调用AfxEndThread函数结束线程。

AfxEndThread函数的定义如下:

void AfxEndThread(UINT nExitCode, BOOL bDelete = TRUE);

其中:

nExitCode:线程的退出码。

在MFC的THRDCORE.CPP中,AfxEndThread函数的相关代码如下:

// THRDCORE.CPP void AFXAPI AfxEndThread(UINT nExitCode, BOOL bDelete) {     // remove current CWinThread object from memory     AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();     CWinThread* pThread = pState->m_pCurrentWinThread;     if (pThread != NULL)     {         ASSERT_VALID(pThread);         ASSERT(pThread != AfxGetApp());         // cleanup OLE if required         if (pThread->m_lpfnOleTermOrFreeLib != NULL)             (*pThread->m_lpfnOleTermOrFreeLib)(TRUE, FALSE);         if (bDelete)             pThread->Delete();         pState->m_pCurrentWinThread = NULL;     }     // allow cleanup of any thread local objects     AfxTermThread();     // allow C-runtime to cleanup, and exit the thread     _endthreadex(nExitCode); }

从MFC代码中可以看出,AfxEndThread函数通过调用_endthreadex函数终止线程。此外,函数还进行释放线程的堆栈、删除线程对象等工作。

如果在其它线程中终止该线程,必须采用线程通信的方法实现。其中一种简单的方法是建立一个变量,让线程监视该变量,当该变量为某个值时,则终止线程。

(1)创建1个基于对话框的应用程序,名称为Demo。

(2)在IDD_DEMO_DIALOG对话框资源中添加控件,如表所示。

类型ID标题
StaticIDC_STATIC数据:
EditIDC_DATA
ButtonIDC_BEGIN_THREAD启动线程
ButtonIDC_END_THREAD终止线程

// DemoDlg.h typedef struct THREAD_PARAM {     HWND hWnd;     int nData;     BOOL bExit; }_THREAD_PARAM;

(4)在CDemoDlg类中添加成员变量,代码如下:

// DemoDlg.h protected:     CWinThread* m_pThread;     THREAD_PARAM m_ThreadParam;

(5)在CDemoDlg类的构造函数中初始化成员变量,代码如下:

// DemoDlg.cpp CDemoDlg::CDemoDlg(CWnd* pParent /*=NULL*/) : CDialog(CDemoDlg::IDD, pParent) {     // ...     m_pThread = NULL;     m_ThreadParam.nData = 0; }

(6)在CDemoDlg类的OnInitDialog函数中添加如下代码:

// DemoDlg.cpp    BOOL CDemoDlg::OnInitDialog() {     CDialog::OnInitDialog();     //     SetDlgItemInt(IDC_DATA, m_nData);     return TRUE; }

(7)在文件中定义线程消息,代码如下:

// DemoDlg.h #define WM_THREADMSG WM_USER+1

(8)在文件中定义线程函数,代码如下:

// DemoDlg.h UINT ThreadProc(LPVOID pParam); // DemoDlg.cpp UINT ThreadProc(LPVOID pParam) {     //线程参数     THREAD_PARAM* pThreadParam = (THREAD_PARAM*)pParam;     while (!pThreadParam->bExit)     {         Sleep(100);         pThreadParam->nData++;         //向主线程窗口发送消息         ::PostMessage(pThreadParam->hWnd, WM_THREADMSG, 0, 0);     }     return 0; }

(9)在CDemoDlg类中分别为Button控件添加BN_CLICKED添加消息处理函数,代码如下:

// DemoDlg.cpp void CDemoDlg::OnBeginThread() {     if (m_pThread != NULL)     {         AfxMessageBox(_T("线程已经启动。"));         return;     }     m_ThreadParam.hWnd = m_hWnd;     m_ThreadParam.bExit = FALSE;          //启动线程,初始为挂起状态     m_pThread = AfxBeginThread(ThreadProc, &m_ThreadParam,     THREAD_PRIORITY_ABOVE_NORMAL, 0, CREATE_SUSPENDED);          //线程结束时不自动删除     m_pThread->m_bAutoDelete = FALSE;          //恢复线程运行     m_pThread->ResumeThread(); }  void CDemoDlg::OnEndThread() {     if (m_pThread == NULL)     {         AfxMessageBox(_T("线程已经终止。"));         return;     }     m_ThreadParam.bExit = TRUE;          //等待线程结束     ::WaitForSingleObject(m_pThread->m_hThread, INFINITE);     delete m_pThread;     m_pThread = NULL; }

(10)在CDemoDlg类中添加自定义消息处理函数,代码如下:

// DemoDlg.h afx_msg LRESULT OnMsgFunc();  // DemoDlg.cpp BEGIN_MESSAGE_MAP(CDemoDlg, CDialog)     ON_MESSAGE(WM_THREADMSG, OnMsgFunc) END_MESSAGE_MAP()  LRESULT CDemoDlg::OnMsgFunc() {     SetDlgItemInt(IDC_DATA, m_ThreadParam.nData);     return 1;   }


文章来源: 安全终止MFC线程
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!