以下是 MFC 用戶界面線程相關知識
由於用戶界面線程含有自己的消息循環,可以出來 Windows 消息,並可創建和管理諸如窗口和控件等用戶界面元素。因此,這種線程較工程線程更爲複雜。
創建用戶界面線程的起點是從 MFC 的 CWinThread 類派生一個定製的線程類,而不是調用 AfxBeginThread() 函數。定製的線程類必須重載 InitInstance() 函數,該函數用來執行初始化任務,在創建線程時系統將調用 InitInstance() 函數。最好還要重載 ExitInstance() 函數,該函數是 InitInstance() 函數的對應, MFC在刪除線程對象之前會調用 ExitInstance() 函數,以便線程能夠在結束後清除自身。
用戶界面線程的創建有兩種方法:
方法一:首先從 CWinThread 類派生一個類(必須要用宏 DECLARE_DYNCREATE 和 IMPLEMENT_DYNCREATE 對該類進行聲明和實現),然後調用 AfxBeginThread() 創建 CWinThread
派生類的對象進行初始化,啓動線程運行。
方法二:先通過構造函數創建派生類 CWinThread 的一個對象,然後由程序員調用函數 ::CreateThread 來啓動線程。通常CWinThread 派生類的對象在該線程的生存週期結束時將自動終止,如果程序員希望自己來控制,則需要將 m_bAutoDelete 設置爲FALSE。這樣在線程終止之後, CWinThread 派生類對象仍然存在,此時需要手動刪除CWinThread 對象。
MFC 消息處理相關知識
函數原型:LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
函數原型:BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
區別:
PostMessage 將一個消息放入(寄送)到與指定窗口創建的線程相聯繫的消息隊列裏,完成則立即返回(不等待線程處理消息就返回)。消息隊列裏的消息通過調用 GetMessage 和 PeekMessage 取得。
SendMessage 將指定的消息發送到一個或多個窗口。此函數爲指定的窗口調用窗口程序, 直到窗口程序處理完消息再返回。
消息映射: ON_MESSAGE 和 ON_THREAD_MESSAGE
用戶自定義消息通常定義在 WM_USER (0x0400)至 0x7FFF 範圍內,用戶定義的任何消息都不是正規的windows 窗口消息WM_MESSAGE 。用戶自定義消息必須明確地在程序中用ON_MESSAGE
宏來聲明,從而綁定一個消息響應函數。
ON_MESSAGE : 綁定一個自定義的消息和該消息的響應函數。
ON_THREAD_MESSAGE : 當使用 CWinThread 類的時候,必須用 ON_THREAD_MESSAGE 來代替 ON_MESSAGE。
特別注意:使用用戶界面線程時,推送消息用 CWinThread 的成員函數 PostThreadMessage(UINT Msg, WPARAM wParam, LPARAM lParam);
m_childThread->PostThreadMessage(xxx,xxx,xxx); 其推送的消息只對本身類 對象實例。其他對象實例無法接收該消息。簡單的說就是每個對象實例擁有內部消息棧,不共享。所以採用消息機制做多線程是不適合動態創建若干線程,且每個線程正常工作。
退出線程發送 WM_QUIT 消息。
MFC用戶界面線程實例:
一、採用消息循環的用戶界面線程實例
頭文件:
/*
* Copyright (c) 2014-2020, MFC多線程學習
* All rights reserved.
*
* 文件名稱:FireUIThreadMsg.h
* 文件標識:
* 摘 要:MFC用戶界面線程,採用MFC消息機制
*
* 當前版本:1.0
* 作 者:XXX
* 完成日期:2014-06-16
*
* 取代版本:無
* 原 作 者:
* 完成日期:
*/
#pragma once
#define WM_MSG_FIREUIMSG (WM_USER+11) //自定義用戶消息
// CFireUIThreadMsg
class CFireUIThreadMsg : public CWinThread
{
DECLARE_DYNCREATE(CFireUIThreadMsg)
public:
CFireUIThreadMsg(); // 動態創建所使用的受保護的構造函數
virtual ~CFireUIThreadMsg();
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
public: //用戶添加函數
afx_msg void FireUIWork(WPARAM wParam, LPARAM lParam); //消息處理函數
CBrush m_Brush;
CPoint m_Point;
int m_num;
CFireUIThreadMsg(int num);
void KillThread();
protected:
DECLARE_MESSAGE_MAP()
};
// FireUIThreadMsg.cpp : 實現文件
//
#include "stdafx.h"
#include "Firework.h"
#include "FireUIThreadMsg.h"
// CFireUIThreadMsg
IMPLEMENT_DYNCREATE(CFireUIThreadMsg, CWinThread)
CFireUIThreadMsg::CFireUIThreadMsg()
{
m_bAutoDelete = FALSE;
}
CFireUIThreadMsg::~CFireUIThreadMsg()
{
}
BOOL CFireUIThreadMsg::InitInstance()
{
// TODO: 在此執行任意逐線程初始化
return TRUE;
}
int CFireUIThreadMsg::ExitInstance()
{
// TODO: 在此執行任意逐線程清理
return CWinThread::ExitInstance();
}
BEGIN_MESSAGE_MAP(CFireUIThreadMsg, CWinThread)
ON_THREAD_MESSAGE(WM_MSG_FIREUIMSG, &CFireUIThreadMsg::FireUIWork) //消息映射宏
END_MESSAGE_MAP()
// CFireUIThreadMsg 消息處理程序
void CFireUIThreadMsg::FireUIWork(WPARAM wParam, LPARAM lParam)
{
CString tem;
tem.Format("%d", m_num);
AfxMessageBox(tem);
}
CFireUIThreadMsg::CFireUIThreadMsg(int num)
{
m_num = num;
}
void CFireUIThreadMsg::KillThread()
{
PostThreadMessage(WM_QUIT, 0 , 0);
}
二、採用事件等待循環處理實例
頭文件:
/*
* Copyright (c) 2014-2020, MFC多線程學習
* All rights reserved.
*
* 文件名稱:FireUIThread.h
* 文件標識:
* 摘 要:MFC用戶界面線程,採用循環機制。不使用MFC消息
* 適用於動態創建大量線程。
*
* 當前版本:1.0
* 作 者:XXX
* 完成日期:2014-06-16
*
* 取代版本:無
* 原 作 者:
* 完成日期:
*/
#pragma once
// CFireUIThread
class CFireUIThread : public CWinThread
{
DECLARE_DYNCREATE(CFireUIThread)
//protected:
public:
CFireUIThread(); // 動態創建所使用的受保護的構造函數
CFireUIThread(CDC *pDC, CRect rect);
virtual ~CFireUIThread();
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
virtual void Delete();
protected:
DECLARE_MESSAGE_MAP()
public:
void FireworkDisplay();
void KillThread();
private:
HANDLE m_hEventKill;
HANDLE m_hEventDead;
};
源文件:
// FireUIThread.cpp : 實現文件
//
#include "stdafx.h"
#include "Firework.h"
#include "FireUIThread.h"
// CFireUIThread
IMPLEMENT_DYNCREATE(CFireUIThread, CWinThread)
CFireUIThread::CFireUIThread()
{
m_bAutoDelete = FALSE;
m_hEventKill = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hEventDead = CreateEvent(NULL, TRUE, FALSE, NULL);
}
CFireUIThread::~CFireUIThread()
{
CloseHandle(m_hEventKill);
CloseHandle(m_hEventDead);
}
BOOL CFireUIThread::InitInstance()
{
// TODO: 在此執行任意逐線程初始化
while (WaitForSingleObject(m_hEventKill, 0) == WAIT_TIMEOUT)
{
FireworkDisplay();
}
//return TRUE;
// avoid entering standard message loop by returning FALSE
return FALSE; //不進入消息循環。特別注意
}
int CFireUIThread::ExitInstance()
{
// TODO: 在此執行任意逐線程清理
return CWinThread::ExitInstance();
}
void CFireUIThread::Delete()
{
CWinThread::Delete();
SetEvent(m_hEventDead);
}
void CFireUIThread::KillThread()
{
SetEvent(m_hEventKill);
SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
WaitForSingleObject(m_hEventDead, INFINITE);
delete this;
}
BEGIN_MESSAGE_MAP(CFireUIThread, CWinThread)
END_MESSAGE_MAP()
// CFireUIThread 消息處理程序
void CFireUIThread::FireworkDisplay()
{
//線程處理函數
}
創建線程代碼片:
CWinThread* pThread = new CFireUIThreadMsg(nIDTimerEvent);
pThread->CreateThread(CREATE_SUSPENDED);
pThread->ResumeThread();//運行
記得結束線程,釋放內存。