基于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()得到了一个当前窗口的句柄,此消息将发给当前窗口,如果想发送消息给其它窗口只需改变这个句柄,前提是目的窗口也实现了此消息的处理函数。