可以在一个线程的执行函数中向另一个线程发送自定义的消息来达到通信的目的.一个线程向另外一个线程发送消息是通过操作系统实现的.利用 Windows 操作系统的消息驱动机制,当一个线程发出一条消息时,操作系统首先接收到该消息,然后把该消息转发给目标线程,接收消息的线程必须已经建立了消息循环.
例程 7 MultiThread7
该例程演示了如何使用自定义消息进行线程间通信.首先,主线程向 CCalculateThread 线程发送消息WM_CALCULATE,CCalculateThread 线程收到消息后进行计算,再向主线程发送 WM_DISPLAY 消息,主线程收到该消息后显示计算结果.
建立一个基于对话框的工程 MultiThread7,在对话框 IDD_MULTITHREAD7_DIALOG 中加入三个单选按钮IDC_RADIO1,IDC_RADIO2,IDC_RADIO3,标题分别为1+2+3+4+......+10,1+2+3+4+......+50,1+2+3+4+......+100.加入按钮 IDC_SUM,标题为“求和”.加入标签框 IDC_STATUS,属性选中“边框”.
分别双击三个单选按钮,添加消息响应函数:
void CMultiThread7Dlg::OnRadio1()
{
nAddend=10;
}
void CMultiThread7Dlg::OnRadio2()
{
nAddend=50;
}
void CMultiThread7Dlg::OnRadio3()
{
nAddend=100;
}
并在 OnInitDialog 函数中完成相应的初始化工作:
1 BOOL CMultiThread7Dlg::OnInitDialog() 2 { 3 CDialogEx::OnInitDialog(); 4 5 // 将“关于...”菜单项添加到系统菜单中。 6 7 // IDM_ABOUTBOX 必须在系统命令范围内。 8 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 9 ASSERT(IDM_ABOUTBOX < 0xF000); 10 11 CMenu* pSysMenu = GetSystemMenu(FALSE); 12 if (pSysMenu != NULL) 13 { 14 BOOL bNameValid; 15 CString strAboutMenu; 16 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 17 ASSERT(bNameValid); 18 if (!strAboutMenu.IsEmpty()) 19 { 20 pSysMenu->AppendMenu(MF_SEPARATOR); 21 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 22 } 23 } 24 25 // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 26 // 执行此操作 27 SetIcon(m_hIcon, TRUE); // 设置大图标 28 SetIcon(m_hIcon, FALSE); // 设置小图标 29 30 // TODO: 在此添加额外的初始化代码 31 ((CButton*)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE); 32 nAddend = 10; 33 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE 34 }
在 MultiThread7Dlg.h 中添加: #include "CalculateThread.h"
1 // MultiThread7Dlg.h : 头文件 2 // 3 #include "CalculateThread.h" 4 5 6 #define WM_DISPLAY WM_USER+2 7 8 #pragma once 9 10 11 // CMultiThread7Dlg 对话框 12 class CMultiThread7Dlg : public CDialogEx 13 { 14 // 构造 15 public: 16 CMultiThread7Dlg(CWnd* pParent = NULL); // 标准构造函数 17 CCalculateThread *m_pCalculateThread; 18 // 对话框数据 19 #ifdef AFX_DESIGN_TIME 20 enum { IDD = IDD_MULTITHREAD7_DIALOG }; 21 #endif 22 23 protected: 24 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 25 26 27 // 实现 28 protected: 29 HICON m_hIcon; 30 int nAddend; 31 LRESULT OnDisplay(WPARAM wParam, LPARAM lParam); 32 // 生成的消息映射函数 33 virtual BOOL OnInitDialog(); 34 afx_msg void OnSysCommand(UINT nID, LPARAM lParam); 35 afx_msg void OnPaint(); 36 afx_msg HCURSOR OnQueryDragIcon(); 37 DECLARE_MESSAGE_MAP() 38 public: 39 afx_msg void OnBnClickedRadio1(); 40 afx_msg void OnBnClickedRadio2(); 41 afx_msg void OnBnClickedRadio3(); 42 afx_msg void OnBnClickedSum(); 43 };
在 MultiThread7Dlg.cpp 中添加: BEGIN_MESSAGE_MAP(CMultiThread7Dlg, CDialog)
1 // MultiThread7Dlg.cpp : 实现文件 2 // 3 4 #include "stdafx.h" 5 #include "MultiThread7.h" 6 #include "MultiThread7Dlg.h" 7 #include "afxdialogex.h" 8 9 #ifdef _DEBUG 10 #define new DEBUG_NEW 11 #endif 12 13 14 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 15 16 class CAboutDlg : public CDialogEx 17 { 18 public: 19 CAboutDlg(); 20 21 // 对话框数据 22 #ifdef AFX_DESIGN_TIME 23 enum { IDD = IDD_ABOUTBOX }; 24 #endif 25 26 protected: 27 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 28 29 // 实现 30 protected: 31 DECLARE_MESSAGE_MAP() 32 }; 33 34 CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) 35 { 36 } 37 38 void CAboutDlg::DoDataExchange(CDataExchange* pDX) 39 { 40 CDialogEx::DoDataExchange(pDX); 41 } 42 43 BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) 44 END_MESSAGE_MAP() 45 46 47 // CMultiThread7Dlg 对话框 48 49 50 51 CMultiThread7Dlg::CMultiThread7Dlg(CWnd* pParent /*=NULL*/) 52 : CDialogEx(IDD_MULTITHREAD7_DIALOG, pParent) 53 { 54 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 55 } 56 57 void CMultiThread7Dlg::DoDataExchange(CDataExchange* pDX) 58 { 59 CDialogEx::DoDataExchange(pDX); 60 } 61 62 BEGIN_MESSAGE_MAP(CMultiThread7Dlg, CDialogEx) 63 ON_WM_SYSCOMMAND() 64 ON_WM_PAINT() 65 ON_WM_QUERYDRAGICON() 66 ON_BN_CLICKED(IDC_RADIO1, &CMultiThread7Dlg::OnBnClickedRadio1) 67 ON_BN_CLICKED(IDC_RADIO2, &CMultiThread7Dlg::OnBnClickedRadio2) 68 ON_BN_CLICKED(IDC_RADIO3, &CMultiThread7Dlg::OnBnClickedRadio3) 69 ON_MESSAGE(WM_DISPLAY, &CMultiThread7Dlg::OnDisplay) 70 ON_BN_CLICKED(IDC_SUM, &CMultiThread7Dlg::OnBnClickedSum) 71 END_MESSAGE_MAP() 72 73 74 // CMultiThread7Dlg 消息处理程序 75 76 BOOL CMultiThread7Dlg::OnInitDialog() 77 { 78 CDialogEx::OnInitDialog(); 79 80 // 将“关于...”菜单项添加到系统菜单中。 81 82 // IDM_ABOUTBOX 必须在系统命令范围内。 83 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 84 ASSERT(IDM_ABOUTBOX < 0xF000); 85 86 CMenu* pSysMenu = GetSystemMenu(FALSE); 87 if (pSysMenu != NULL) 88 { 89 BOOL bNameValid; 90 CString strAboutMenu; 91 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 92 ASSERT(bNameValid); 93 if (!strAboutMenu.IsEmpty()) 94 { 95 pSysMenu->AppendMenu(MF_SEPARATOR); 96 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 97 } 98 } 99 100 // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 101 // 执行此操作 102 SetIcon(m_hIcon, TRUE); // 设置大图标 103 SetIcon(m_hIcon, FALSE); // 设置小图标 104 105 // TODO: 在此添加额外的初始化代码 106 ((CButton*)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE); 107 nAddend = 10; 108 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE 109 } 110 111 void CMultiThread7Dlg::OnSysCommand(UINT nID, LPARAM lParam) 112 { 113 if ((nID & 0xFFF0) == IDM_ABOUTBOX) 114 { 115 CAboutDlg dlgAbout; 116 dlgAbout.DoModal(); 117 } 118 else 119 { 120 CDialogEx::OnSysCommand(nID, lParam); 121 } 122 } 123 124 // 如果向对话框添加最小化按钮,则需要下面的代码 125 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, 126 // 这将由框架自动完成。 127 128 void CMultiThread7Dlg::OnPaint() 129 { 130 if (IsIconic()) 131 { 132 CPaintDC dc(this); // 用于绘制的设备上下文 133 134 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); 135 136 // 使图标在工作区矩形中居中 137 int cxIcon = GetSystemMetrics(SM_CXICON); 138 int cyIcon = GetSystemMetrics(SM_CYICON); 139 CRect rect; 140 GetClientRect(&rect); 141 int x = (rect.Width() - cxIcon + 1) / 2; 142 int y = (rect.Height() - cyIcon + 1) / 2; 143 144 // 绘制图标 145 dc.DrawIcon(x, y, m_hIcon); 146 } 147 else 148 { 149 CDialogEx::OnPaint(); 150 } 151 } 152 153 //当用户拖动最小化窗口时系统调用此函数取得光标 154 //显示。 155 HCURSOR CMultiThread7Dlg::OnQueryDragIcon() 156 { 157 return static_cast<HCURSOR>(m_hIcon); 158 } 159 160 161 162 void CMultiThread7Dlg::OnBnClickedRadio1() 163 { 164 // TODO: 在此添加控件通知处理程序代码 165 nAddend = 10; 166 } 167 168 169 void CMultiThread7Dlg::OnBnClickedRadio2() 170 { 171 // TODO: 在此添加控件通知处理程序代码 172 nAddend = 50; 173 } 174 175 176 void CMultiThread7Dlg::OnBnClickedRadio3() 177 { 178 // TODO: 在此添加控件通知处理程序代码 179 nAddend = 100; 180 } 181 182 183 184 LRESULT CMultiThread7Dlg::OnDisplay(WPARAM wParam, LPARAM lParam) 185 { 186 int nTemp = (int)wParam; 187 SetDlgItemInt(IDC_STATUS, nTemp, FALSE); 188 return 0; 189 } 190 191 void CMultiThread7Dlg::OnBnClickedSum() 192 { 193 // TODO: 在此添加控件通知处理程序代码 194 m_pCalculateThread = (CCalculateThread *) AfxBeginThread(RUNTIME_CLASS(CCalculateThread)); 195 Sleep(500); 196 m_pCalculateThread->PostThreadMessage(WM_CALCULATE, nAddend, NULL); 197 m_pCalculateThread = NULL; 198 }
CalculateThread.h
1 #pragma once 2 #include "afxwin.h" 3 4 #define WM_CALCULATE WM_USER+1 5 6 7 class CCalculateThread :public CWinThread 8 { 9 10 DECLARE_DYNCREATE(CCalculateThread) 11 protected: 12 CCalculateThread(); 13 ~CCalculateThread(); 14 public: 15 16 virtual BOOL InitInstance(); 17 virtual int ExitInstance(); 18 19 afx_msg void OnCalculate(UINT wParam, LONG lParam); 20 21 protected: 22 23 DECLARE_MESSAGE_MAP() 24 };
CalculateThread.cpp
1 #include "stdafx.h" 2 #include "CalculateThread.h" 3 #include "MultiThread7Dlg.h" 4 5 IMPLEMENT_DYNCREATE(CCalculateThread, CWinThread) 6 7 BEGIN_MESSAGE_MAP(CCalculateThread, CWinThread) 8 //{{AFX_MSG_MAP(CCalculateThread) 9 // NOTE - the ClassWizard will add and remove mapping macros here. 10 //}}AFX_MSG_MAP 11 ON_THREAD_MESSAGE(WM_CALCULATE, &CCalculateThread::OnCalculate) 12 //和主线程对比,注意它们的区别 13 END_MESSAGE_MAP() 14 15 CCalculateThread::CCalculateThread() 16 { 17 } 18 19 20 CCalculateThread::~CCalculateThread() 21 { 22 AfxEndThread(0); 23 } 24 25 26 BOOL CCalculateThread::InitInstance() 27 { 28 // TODO: 在此执行任意逐线程初始化 29 return TRUE; 30 } 31 32 int CCalculateThread::ExitInstance() 33 { 34 // TODO: 在此执行任意逐线程清理 35 return CWinThread::ExitInstance(); 36 } 37 38 39 void CCalculateThread::OnCalculate(UINT wParam, LONG lParam) 40 { 41 int nTmpt = 0; 42 for (int i = 0; i <= (int)wParam; i++) 43 { 44 nTmpt = nTmpt + i; 45 } 46 Sleep(500); 47 ::PostMessage((HWND)(GetMainWnd()->GetSafeHwnd()), WM_DISPLAY, nTmpt, NULL); 48 //return 0; 49 }