MFC用戶界面多線程實例2

         以下是 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();//運行

記得結束線程,釋放內存。



發佈了34 篇原創文章 · 獲贊 6 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章