基於MFC的多線程
具體示例如下:
1、創建CWndThread的子類,實現用戶界面多線程
實現代碼如下
UIThread.h
#pragma once
//包含的對話框頭文件
#include "DlgSubThread.h"
// CUIThread
class CUIThread : public CWinThread
{
DECLARE_DYNCREATE(CUIThread)
//protected:
public://改爲public
CUIThread(HWND mHwnd); //自定義添加的構造函數,用來傳遞參數(調用此線程的窗口句柄)
CUIThread(); // 動態創建所使用的受保護的構造函數
protected:
virtual ~CUIThread();
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
protected:
DECLARE_MESSAGE_MAP()
protected:
CDlgSubThread m_dlgSub;//對話框對象
HWND m_Hwnd; //窗口句柄
};
// UIThread.cpp : 實現文件
//
#include "stdafx.h"
#include "DemoThread1.h"
#include "UIThread.h"
// CUIThread
IMPLEMENT_DYNCREATE(CUIThread, CWinThread)
CUIThread::CUIThread()
{
}
//添加自定義構造函數,傳遞參數(窗口句柄)
CUIThread::CUIThread(HWND mHwnd)
{
m_Hwnd=mHwnd;
}
CUIThread::~CUIThread()
{
}
BOOL CUIThread::InitInstance()
{
// TODO: 在此執行任意逐線程初始化
//CFrameWnd* wnd=new CFrameWnd;
//wnd->Create(NULL,"UI thread window");
//wnd->ShowWindow(SW_SHOW);
//wnd->UpdateWindow();
//m_pMainWnd=wnd;
m_dlgSub.Create(IDD_DIALOG1);
m_dlgSub.ShowWindow(SW_SHOW);
m_dlgSub.SetHWND(m_Hwnd);
m_pMainWnd=&m_dlgSub;
return TRUE;
}
int CUIThread::ExitInstance()
{
// TODO: 在此執行任意逐線程清理
m_dlgSub.DestroyWindow();
return CWinThread::ExitInstance();
}
BEGIN_MESSAGE_MAP(CUIThread, CWinThread)
END_MESSAGE_MAP()
// CUIThread 消息處理程序
2、添加對話框資源並添加對應的類 CDlgSubThread
界面如下
添加相應的處理函數
DlgSubThread.h文件
#pragma once
// CDlgSubThread 對話框
class CDlgSubThread : public CDialog
{
DECLARE_DYNAMIC(CDlgSubThread)
public:
CDlgSubThread(CWnd* pParent = NULL); // 標準構造函數
virtual ~CDlgSubThread();
// 對話框數據
enum { IDD = IDD_DIALOG1 };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
DECLARE_MESSAGE_MAP()
public:
void SetHWND(HWND mHwnd);//設置傳遞的窗口句柄
HWND m_Hwnd2; //窗口句柄,外面穿進來的
afx_msg void OnBnClickedButton1();
afx_msg void OnBnClickedButton2();
afx_msg void OnBnClickedButton3();
};
// DlgSubThread.cpp : 實現文件
//終止線程
void CDlgSubThread::OnBnClickedButton2()
{
PostQuitMessage(0);
}
//設置句柄
void CDlgSubThread::SetHWND(HWND mHwnd)
{
m_Hwnd2=mHwnd;
}
//發送消息到調用此線程的窗口
void CDlgSubThread::OnBnClickedButton3()
{
//發送消息
CString msg;
(GetDlgItem(IDC_EDIT1))->GetWindowText(msg);
//char * msgc=msg.GetBuffer(0);//傳遞指針(數據的地址)用這種方式轉換後的字符串在發送消息的過程時會發生亂碼,要改用下面的方式
char * msgc=new char[msg.GetLength()+1];
memset(msgc,0,msg.GetLength()+1);
strcpy(msgc,msg);
::PostMessage(m_Hwnd2,WM_USER_THREADEND,(WPARAM)msgc,0);
}
3、添加自定義消息 在// stdafx.h 中
//自定義消息宏
#define WM_USER_THREADEND WM_USER + 1
4、實現線程的調用和消息的處理
DemoThread1Dlg.h
//在增加新消息的窗口或對話框類的頭文件中增加一個回調函數聲明,注意要聲明爲public
afx_msg LRESULT OnUserThreadend(WPARAM wParam, LPARAM lParam);
// DemoThread1Dlg.cpp : 實現文件
BEGIN_MESSAGE_MAP(CDemoThread1Dlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_BTN_START1, &CDemoThread1Dlg::OnBnClickedBtnStart1)
ON_BN_CLICKED(IDC_BTN_START2, &CDemoThread1Dlg::OnBnClickedBtnStart2)
ON_BN_CLICKED(IDC_BUTTON1, &CDemoThread1Dlg::OnBnClickedButton1)
//添加消息映射
ON_MESSAGE(WM_USER_THREADEND, OnUserThreadend)
END_MESSAGE_MAP()
void CDemoThread1Dlg::OnBnClickedBtnStart2()
{
//第一種 啓動線程,這種方式無法傳遞參數
//CWinThread *pThread=AfxBeginThread(RUNTIME_CLASS(CUIThread));
//第二種 啓動線程
//CUIThread* pThread=new CUIThread();
//pThread->CreateThread();
//第二種 啓動線程,傳遞參數(本窗口句柄,用來接收消息)
//CUIThread* pThread=new CUIThread(GetSafeHwnd());
//pThread->CreateThread();
//測試,只有一個線程實例運行//bool ExitThread=false,在頭文件中定義賦初值爲false
if (ExitThread)
{
DWORD exitFlag=0;
GetExitCodeThread(threadSubDlg,&exitFlag);
if (!exitFlag)
{
TRACE("結束\r\n");
ExitThread=FALSE;
}
}
if (!ExitThread)
{
CUIThread* pThread=new CUIThread(GetSafeHwnd());
pThread->CreateThread();
threadSubDlg=pThread->m_hThread;
ExitThread=TRUE;
}
}
//消息響應
LRESULT CDemoThread1Dlg::OnUserThreadend(WPARAM wParam, LPARAM lParam)
{
//TRACE("WM_USER_THREADEND message \r\n");
//CString str((char*)lParam;
CString msg=(char*)wParam;
TRACE(msg+"\r\n");
return 0;
}
一般而言,應用程序中的一個次要線程總是爲主線程執行特定的任務,這樣,主線程和次要線程間必定有一個信息傳遞的渠道,也就是主線程和次要線程間要進行通信。這種線程間的通信不但是難以避免的,而且在多線程編程中也是複雜和頻繁的,下面將進行說明。
- 使用全局變量進行通信
由於屬於同一個進程的各個線程共享操作系統分配該進程的資源,故解決線程間通信最簡單的一種方法是使用全局變量。對於標準類型的全局變量,建議使用volatile 修飾符,它告訴編譯器無需對該變量作任何的優化,即無需將它放到一個寄存器中,並且該值可被外部改變。如果線程間所需傳遞的信息較複雜,我們可以定義一個結構,通過傳遞指向該結構的指針進行傳遞信息。
- 使用自定義消息
我們可以在一個線程的執行函數中向另一個線程發送自定義的消息來達到通信的目的。一個線程向另外一個線程發送消息是通過操作系統實現的。利用 Windows操作系統的消息驅動機制,當一個線程發出一條消息時,操作系統首先接收到該消息,然後把該消息轉發給目標線程,接收消息的線程必須已經建立 了消息循環。
1. 在頭文件stdafx.h中增加一個自定義消息宏
#define WM_USER_THREADEND WM_USER + 1
2. 在增加新消息的窗口或對話框類的頭文件中增加一個回調函數聲明,注意要聲明爲public
afx_msg LRESULT OnUserThreadend(WPARAM wParam, LPARAM lParam);
3. 在窗口或對話框的cpp文件的BEGIN_MESSAGE_MAP,END_MESSAGE_MAP 中增加一行
ON_MESSAGE(WM_USER_THREADEND, OnUserThreadend)
4. 在窗口或對話框的cpp文件中增加回調函數的實現,如:
LRESULT ThreadDialog::OnUserThreadend(WPARAM wParam, LPARAM lParam)
{
TRACE("WM_USER_THREADEND message /n");
return 0;
}
5. 自定義消息的觸發
::PostMessage(GetSafeHwnd(), WM_USER_THREADEND, 0, 0);
其中GetSafeHwnd()得到了一個當前窗口的句柄,此消息將發給當前窗口,如果想發送消息給其它窗口只需改變這個句柄,前提是目的窗口也實現了此消息的處理函數。