轉(zhuǎn)載自:http://www.cppblog.com/qinqing1984/archive/2009/04/15/80038.html
首先聲明, 這里的工作線程與UI線程是相對的,即沒有任何窗口的. 如果需要與主線程或其它輔助線程通訊,有幾種方法如事件,消息,信號等,也可以是以上幾種方法的綜合運用.下面就列出以下3種通訊方法的代碼框架
(1)只用消息通訊
- DWORD ThreadProc(LPVOID lParam)
- {
- //創(chuàng)建線程消息隊列
- MSG msg;
- PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
- //通知其它線程消息隊列已創(chuàng)建好
- SetEvent(hEvent);
- while(true)
- {
- GetMessage(&msg, NULL, 0, 0);
- switch(msg.message)
- {
- case WM_QUIT:
- return 1;
- //自定義消息1處理
- case WM_USER + 100:
- break;
- //自定義消息2處理
- case WM_USER + 101:
- break;
- }
- }
- return 0;
- }
DWORD ThreadProc(LPVOID lParam){ //創(chuàng)建線程消息隊列 MSG msg; PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); //通知其它線程消息隊列已創(chuàng)建好 SetEvent(hEvent); while(true) { GetMessage(&msg, NULL, 0, 0); switch(msg.message) { case WM_QUIT: return 1; //自定義消息1處理 case WM_USER + 100: break; //自定義消息2處理 case WM_USER + 101: break; } } return 0;}
(2)只用事件通訊
- DWORD ThreadProc(LPVOID lParam)
- {
- DWORD dwIndex;
- while (true)
- {
- dwIndex = WaitForMultipleObjects(cObjects, pObjects, FALSE, INFINTE);
- if (WAIT_OBJECT + 0== dwIndex)
- {
- return 1; //假設(shè)為退出事件
- }
- else if (WAIT_OBJECT + 1 == dwIndex)
- {
- //事件1, 處理程序
- }
- else if (WAIT_OBJECT + cObjects - 1 == dwIndwx)
- {
- //事件2, 處理程序
- }
- }
- }
DWORD ThreadProc(LPVOID lParam){ DWORD dwIndex; while (true) { dwIndex = WaitForMultipleObjects(cObjects, pObjects, FALSE, INFINTE); if (WAIT_OBJECT + 0== dwIndex) { return 1; //假設(shè)為退出事件 } else if (WAIT_OBJECT + 1 == dwIndex) { //事件1, 處理程序 } else if (WAIT_OBJECT + cObjects - 1 == dwIndwx) { //事件2, 處理程序 } }}
(3)用消息和事件通訊
- DWORD ThreadProc(LPVOID lParam)
- {
- while (TRUE)
- {
- DWORD ret ;
- MSG msg ;
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- switch(msg.message)
- {
- //線程退出消息,直接返回
- case WM_QUIT:
- return 1;
- //自定義消息1處理
- case WM_USER + 100:
- break;
- //自定義消息2處理
- case WM_USER + 101:
- break;
- }
- }
- ret = MsgWaitForMultipleObjects(cObjects, lphObjects, FALSE,INFINITE,QS_POSTMESSAGE);
- if (ret == (WAIT_OBJECT_0 + cObjects))
- {
- //有新的消息到來,繼續(xù)到上步PeekMessage處理
- continue;
- }
- else
- {
- //事件處理
- if (ret == WAIT_OBJECT_O)
- {
- }
- else if (ret == WAIT_OBJECT_O + 1)
- {
- }
- else if(ret == WAIT_OBJECT_O + cObjects - 1)
- {
- }
- }
- return 0;
- }
DWORD ThreadProc(LPVOID lParam){ while (TRUE) { DWORD ret ; MSG msg ; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { switch(msg.message) { //線程退出消息,直接返回 case WM_QUIT: return 1; //自定義消息1處理 case WM_USER + 100: break; //自定義消息2處理 case WM_USER + 101: break; } } ret = MsgWaitForMultipleObjects(cObjects, lphObjects, FALSE,INFINITE,QS_POSTMESSAGE); if (ret == (WAIT_OBJECT_0 + cObjects)) { //有新的消息到來,繼續(xù)到上步PeekMessage處理 continue; } else { //事件處理 if (ret == WAIT_OBJECT_O) { } else if (ret == WAIT_OBJECT_O + 1) { } else if(ret == WAIT_OBJECT_O + cObjects - 1) { } } return 0;}
上面用到了GetMessage和PeekMessage 函數(shù), 這兩者都是從消息隊列取出消息, 不同的是GetMessage從消息隊列刪除消息,并且阻塞調(diào)用線程. PeekMessage則是查詢消息隊列,如果有消息就取出,沒有消息也立即返回, 是否從消息隊列刪除消息由最后一個參數(shù)決定:PM_REMOVE表示刪除,PM_NOREMOVE表示不刪除.可以簡單地認為,GetMessage是同步的,PeekMessage是異步的。
*******************************************************************************************************
除以上作者所提到的線程通信方法外還有一種利用MFC消息循環(huán)通信的方法,其操作過程如下:
1.從CWnd派生類CSendDataWnd
- #define WM_SENDDATA WM_USER+100
- #define WM_POSTDATA WM_USER+101
- class CSendDataWnd : public CWnd
- {
- public:
- CSendDataWnd();
- protected:
- //{{AFX_MSG(CSendDataWnd)
- LRESULT OnSendData(WPARAM wParam, LPARAM lParam);
- LRESULT OnPostData(WPARAM wParam, LPARAM lParam);
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
- };
- BEGIN_MESSAGE_MAP(CSendDataWnd, CWnd)
- ON_MESSAGE(WM_SENDDATA, OnSendData)
- ON_MESSAGE(WM_POSTDATA, OnPostData)
- END_MESSAGE_MAP()
- CSendDataWnd::CSendDataWnd() {
- }
- LRESULT CSendDataWnd::OnSendData(WPARAM wParam, LPARAM lParam)
- {
- switch(wParam) {
- //自定義消息處理
- }
- return 0;
- }
- LRESULT CSendDataWnd::OnPostData( WPARAM wParam, LPARAM lParam )
- {
- switch(wParam) {
- //自定義消息處理
- }
- return 0;
- }
#define WM_SENDDATA WM_USER+100#define WM_POSTDATA WM_USER+101class CSendDataWnd : public CWnd{public: CSendDataWnd();protected: //{{AFX_MSG(CSendDataWnd) LRESULT OnSendData(WPARAM wParam, LPARAM lParam); LRESULT OnPostData(WPARAM wParam, LPARAM lParam); //}}AFX_MSG DECLARE_MESSAGE_MAP()};BEGIN_MESSAGE_MAP(CSendDataWnd, CWnd) ON_MESSAGE(WM_SENDDATA, OnSendData) ON_MESSAGE(WM_POSTDATA, OnPostData)END_MESSAGE_MAP()CSendDataWnd::CSendDataWnd() {}LRESULT CSendDataWnd::OnSendData(WPARAM wParam, LPARAM lParam){ switch(wParam) { //自定義消息處理 } return 0;}LRESULT CSendDataWnd::OnPostData( WPARAM wParam, LPARAM lParam ){ switch(wParam) { //自定義消息處理 } return 0;}
2.聲明CSendDataWnd變量
- CSendDataWnd m_wndSendData;
CSendDataWnd m_wndSendData;
3.調(diào)用CreateEx創(chuàng)建窗口
- if (!m_wndSendData.CreateEx(0, AfxRegisterWndClass(0),
- _T("SendData Notification window"),
- WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL)) {
- TRACE("Create SendData Notification window error!\n");
- AfxThrowResourceException();
- }
if (!m_wndSendData.CreateEx(0, AfxRegisterWndClass(0), _T("SendData Notification window"), WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL)) { TRACE("Create SendData Notification window error!\n"); AfxThrowResourceException();}
4.向CSendDataWnd窗口發(fā)送處理消息
- m_wndSendData.SendMessage(WM_SENDDATA, wParam, lParam);
- //或
- m_wndSendData.PostMessage(WM_POSTDATA, wParam, lParam);
m_wndSendData.SendMessage(WM_SENDDATA, wParam, lParam);//或m_wndSendData.PostMessage(WM_POSTDATA, wParam, lParam);
5.使用完畢后,在適當位置調(diào)用DestroyWindow銷毀消息窗口防止內(nèi)存泄露
- m_wndSendData.DestroyWindow();