對於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
標題
Static
IDC_STATIC
數據:
Edit
IDC_DATA
Button
IDC_BEGIN_THREAD
啟動線程
Button
IDC_END_THREAD
終止線程
(3)在文件中定義線程傳遞參數的數據結構,代碼如下:
// 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;
}