一般而言 ,应用程序中的一个次要线程总是为主线程执行特定的任务,这样,主线程和次要线程间必定有一个信息传递的渠道,也就是主线程和次要线程间要进行通信。这种线程间的通信不但是难以避免的,而且在多线程编程中也是复杂和频繁的,下面将进行说明。
使用全局变量进行通信
由于属于同一个进程的各个线程共享操作系统分配该进程的资源,故解决线程间通信最简单的一种方法是使用全局变量。对于标准类型的全局变量,我们建议使用 volatile 修饰符, 它告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变。如果线程间所需传递的信息较复杂,我们可以定义一个结构,通过传递指向该结构的指针进行传递信息。
使用自定义消息
我们可以在一个线程的执行函数中向另一个线程发送自定义的消息来达到通信的目的。一 个线程向另外一个线程发送消息是通过操作系统实现的。利用 Windows 操作系统的消息驱动机制,当一个线程发出一条消息时,操作系统首先接收到该消息,然后把该消息转发给目标线程,接收消息的线程必须已经建立了消息循环。
例程:MultiThreadCalc
该例程演示了如何使用自定义消息进行线程间通信。首先,主线程向 CCalculateThread线程发送消息 WM_CALCULATE,CCalculateThread 线程收到消息后进行计算,再向主线程发送 WM_DISPLAY 消息,主线程收到该消息后显示计算结果。
建立一个基于对话框的工程 MultiThread7,在对话框 IDD_MULTITHREADCALC_DIALOG中加入三个单选按钮 IDC_RADIO1,IDC_RADIO2,IDC_RADIO3,标题分别为 1+2+3+4+......+10,1+2+3+4+......+50,1+2+3+4+......+100。加入按钮 IDC_BTNADD,标题为“求和”。加入标签框IDC_STATUS,属性选中“边框”;
在 MultiThreadCalcDlg.h 中定义如下变量:
protected: int nAddend;代表加数的大小。
分别双击三个单选按钮,添加消息响应函数:
void CMultiThreadCalcDlg::OnRadio1() { nAddend = 10; } void CMultiThreadCalcDlg::OnRadio2() { nAddend = 50; } void CMultiThreadCalcDlg::OnRadio3() { nAddend = 100; }并在 OnInitDialog 函数中完成相应的初始化工作:
((CButton*)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE); nAddend =10;
在 MultiThreadCalcDlg.h 代码如下:
#include <afxmt.h> #include "CCalculateThread.h" // CMultiThreadCalcDlg dialog #define WM_DISPLAY WM_USER+2 // 自定义消息 class CMultiThreadCalcDlg : public CDialog { // Construction public: CMultiThreadCalcDlg(CWnd* pParent = NULL); // standard constructor CCalculateThread* m_pCalcThread; // Dialog Data //{{AFX_DATA(CMultiThreadCalcDlg) enum { IDD = IDD_MULTITHREADCALC_DIALOG }; // NOTE: the ClassWizard will add data members here //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMultiThreadCalcDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: int nAddend; HICON m_hIcon; // Generated message map functions //{{AFX_MSG(CMultiThreadCalcDlg) virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnRadio1(); afx_msg void OnRadio2(); afx_msg LRESULT OnDisplay(WPARAM wParam, LPARAM lParam); afx_msg void OnRadio3(); afx_msg void OnBtnAdd(); afx_msg void OnChangeEdit1(); //}}AFX_MSG DECLARE_MESSAGE_MAP() };在 MultiThreadCalcDlg.cpp 中的Begin_Message_Map中加WM_DISPLAY消息映射及响应:
ON_MESSAGE(WM_DISPLAY, OnDisplay)
LRESULT CMultiThreadCalcDlg::OnDisplay(WPARAM wParam, LPARAM lParam) { int nTemp = (int)wParam; SetDlgItemInt(IDC_STATIC, nTemp, FALSE); return 0; }以上代码使得主线程类 MultiThreadCalcDlg可以处理 WM_DISPLAY 消息,即在 IDC_STAT US标签框中显示计算结果。双击按钮 IDC_BTN_ADD,添加消息响应函数:
void CMultiThreadCalcDlg::OnBtnAdd() { // TODO: Add your control notification handler code here m_pCalcThread = (CCalculateThread*)AfxBeginThread(RUNTIME_CLASS(CCalculateThread)); Sleep(500); m_pCalcThread->PostThreadMessage(WM_CALCULATE, nAddend, NULL); }
OnBtnAdd()函数的作用是建立CCalculateThread 线程,延时给该线程发送 WM_CALCULATE 消息。
右 击 工 程 并 选 中 “ New Class … ” 为 工 程 添 加 基 类 为 CWinThread 派 生 线 程 类CCal ulateThread。其头文件如下:
#define WM_CALCULATE WM_USER+1 class CCalculateThread : public CWinThread { DECLARE_DYNCREATE(CCalculateThread) protected: CCalculateThread(); // protected constructor used by dynamic creation // Attributes public: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CCalculateThread) public: virtual BOOL InitInstance(); virtual int ExitInstance(); //}}AFX_VIRTUAL // Implementation protected: virtual ~CCalculateThread(); afx_msg long OnCalculate(WPARAM wParam, LPARAM lParam); // Generated message map functions //{{AFX_MSG(CCalculateThread) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG DECLARE_MESSAGE_MAP() };在文件 CCalculateThread.cpp 中添加:
long CCalculateThread::OnCalculate(WPARAM wParam, LPARAM lParam) { int nTmpt = 0; for( int i=0; i<(int)wParam; i++) { nTmpt += i; } Sleep(500); ::PostMessage((HWND)(GetMainWnd()->GetSafeHwnd()),WM_DISPLAY,nTmpt,NULL); return 0; } BEGIN_MESSAGE_MAP(CCalculateThread, CWinThread) //{{AFX_MSG_MAP(CCalculateThread) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP ON_THREAD_MESSAGE(WM_CALCULATE, OnCalculate) END_MESSAGE_MAP()以上代码为 CCalculateThread 类添加了 WM_CALCULATE 消息,消息的响应函数是 OnCalculate,其功能是根据参数 wParam 的值,进行累加,累加结果在临时变量 nTmpt中,延时 0.5 秒,向主线程发送 WM_DISPLAY 消息进行显示,nTmpt 作为参数传递。
工程代码下载:MFC多线程间消息通信工程案例