线程 进程学习之五 线程间的通信

通常情况下,一个次级线程要为主线程完成某种特定类型的任务,这就隐含着表示在主线程和次级线程之间需要建立一个通信的通道。一般情况下,有下面的几种方法实现这种通信任务:使用全局变量(上一节的例子其实使用的就是这种方法)、使用事件对象、使用消息。

一、使用消息通信

在Windows程序设计中,应用程序的每一个线程都拥有自己的消息队列,甚至工作线程也不例外,这样一来,就使得线程之间利用消息来传递信息就变的非常简单。首先用户要定义一个用户消息,如下所示:#define WM_USERMSG WMUSER+100;在需要的时候,在一个线程中调用::PostMessage((HWND)param,WM_USERMSG,0,0)或CwinThread::PostThradMessage()来向另外一个线程发送这个消息,上述函数的四个参数分别是消息将要发送到的目的窗口的句柄、要发送的消息标志符、消息的参数WPARAM和LPARAM。下面的代码是对上节代码的修改,修改后的结果是在线程结束时显示一个对话框,提示线程结束:

UINT ThreadFunction(LPVOID pParam)
{
 while(!bend)
 {
  Beep(100,100);
  Sleep(1000);
 }
 ::PostMessage(hWnd,WM_USERMSG,0,0);
 return 0;
}
WM_USERMSG消息的响应函数为OnThreadended(WPARAM wParam,
LPARAM lParam)
LONG CTestView::OnThreadended(WPARAM wParam,LPARAM lParam)
{
 AfxMessageBox("Thread ended.");
 Retrun 0;
}
  上面的例子是工作者线程向用户界面线程发送消息,对于工作者线程,如果它的设计模式也是消息驱动的,那么调用者可以向它发送初始化、退出、执行某种特定的处理等消息,让它在后台完成。在控制函数中可以直接使用::GetMessage()这个SDK函数进行消息分检和处理,自己实现一个消息循环。GetMessage()函数在判断该线程的消息队列为空时,线程将系统分配给它的时间片让给其它线程,不无效的占用CPU的时间,如果消息队列不为空,就获取这个消息,判断这个消息的内容并进行相应的处理。

消息相应创建:

BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
 //{{AFX_MSG_MAP(CTestDlg)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 ON_MESSAGE(WM_USERMSG,OnSetCommand)
 //}}AFX_MSG_MAP
 ON_WM_DESTROY()
END_MESSAGE_MAP()

 // Generated message map functions
 //{{AFX_MSG(CTestDlg)
 virtual BOOL OnInitDialog();
 afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
 afx_msg void OnPaint();
 afx_msg HCURSOR OnQueryDragIcon();
 virtual void OnOK();
 afx_msg LRESULT   OnSetCommand(WPARAM   wParam,LPARAM   lParam);//
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()

LRESULT CTestDlg::OnSetCommand(WPARAM wParam,LPARAM lParam)
{
 MessageBox("HELLO");
 return 0;
}

遇到的问题:一、ONOK()函数会在窗口销毁前销毁进程,所以无法进行消息的投递;改用Sleep()可解决问题

二、PostMessage()是投递消息,是异步的,不等待返回,因此与创建的线程相互干扰,因用SendMessage

三、必须传递窗口句柄给线程,可以通过GetSafeHwnd()获得

我的案例:

}
UINT ThreadFunction(LPVOID pParm)
{
 ::WaitForSingleObject(threadStart, INFINITE);
 AfxMessageBox("Start...");
 while (!band)
 {
  AfxMessageBox("WAIT_OBJECT_O");
  Sleep(1000);
  Beep(100, 100);
  Sleep(1000);
  DWORD dwRet = ::WaitForSingleObject(threadEnd, 0);
  if (dwRet == WAIT_OBJECT_0)
  {
   AfxMessageBox("WAIT_OBJECT_O");
   band = TRUE;
  }
  Sleep(10);
 }
 DWORD bRet = SendMessage((HWND)pParm, WM_USERMSG, 0, 0);
 //BOOL dwRet = ::PostMessage((HWND)pParm, WM_USERMSG, 0, 0);
 MessageBox(
 return 0;
}
void CTestDlg::OnOK()
{
 // TODO: Add extra validation here
 //HWND hwnd = GetSafeHwnd();
 //DWORD dwThread;
 //hThread = CreateThread(NULL, 0, ThreadFunction, hwnd, 0, &dwThread);
 //DWORD dwRet = GetLastError();
 ///*dwRet = WaitForSingleObject(hThread, 0);
 //if (dwRet == WAIT_OBJECT_0)
 // MessageBox("1");
 //else
 // MessageBox("0");*/
 //Sleep(10);
// HWND hNotifyWnd = GetSafeHwnd();
// BOOL bRet = ::SendMessage(hNotifyWnd, WM_USERMSG, 0, 0);
 //CDialog::OnOK();
 hwnd = GetSafeHwnd();
 SetEvent(threadStart);
 hThread = AfxBeginThread(ThreadFunction, hwnd);
 hThread->m_bAutoDelete = FALSE;
 Sleep(10);
}

LRESULT CTestDlg::OnSetCommand(WPARAM wParam,LPARAM lParam)
{
 MessageBox("HELLO");
 return 0;
}

void CTestDlg::OnDestroy()
{
 BOOL bRet = SetEvent(threadEnd);
 DWORD dwExitCode;
 GetExitCodeThread(hThread->m_hThread,&dwExitCode);
 if (dwExitCode == STILL_ACTIVE)
  MessageBox("active");
 DWORD dwRet = WaitForSingleObject(hThread, INFINITE);
 if (dwRet == WAIT_TIMEOUT)
  MessageBox("...");
 //delete hThread;
 Sleep(10);

 // TODO: Add your message handler code here

(二)用事件对象实现通信

  在线程之间传递信号进行通信比较复杂的方法是使用事件对象,用MFC的Cevent类的对象来表示。事件对象处于两种状态之一:有信号和无信号,线程可以监视处于有信号状态的事件,以便在适当的时候执行对事件的操作。上述例子代码修改如下:


Cevent threadStart ,threadEnd;
UINT ThreadFunction(LPVOID pParam)
{
 ::WaitForSingleObject(threadStart.m_hObject,INFINITE);
 AfxMessageBox("Thread start.");
 while(!bend)
 {
  Beep(100,100);
  Sleep(1000);
  Int result=::WaitforSingleObject(threadEnd.m_hObject,0);
  //等待threadEnd事件有信号,无信号时线程在这里悬停
  If(result==Wait_OBJECT_0)
   Bend=TRUE;
 }
 ::PostMessage(hWnd,WM_USERMSG,0,0);
 return 0;
}
/
Void CtestView::OninitialUpdate()
{
 hWnd=GetSafeHwnd();
 threadStart.SetEvent();//threadStart事件有信号
 pThread=AfxBeginThread(ThreadFunction,hWnd);//启动线程
 pThread->m_bAutoDelete=FALSE;
 Cview::OnInitialUpdate();
}

Void CtestView::OnDestroy()
{
 threadEnd.SetEvent();
 WaitForSingleObject(pThread->m_hThread,INFINITE);
 delete pThread;
 Cview::OnDestroy();
}
  运行这个程序,当关闭程序时,才显示提示框,显示"Thread ended"。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值