博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
VC 线程通信的3种方法
阅读量:4111 次
发布时间:2019-05-25

本文共 3173 字,大约阅读时间需要 10 分钟。

1.使用全局变量
   实现线程间通信的方法有很多,常用的主要是通过全局变量、自定义消息和事件对象等来实现的。其中又以对全局变量的使用最为简洁。该方法将全局变量作为线程监视的对象,并通过在主线程对此变量值的改变而实现对子线程的控制。
   由于这里的全局变量需要在使用它的线程之外对其值进行改变,这就需要通过volatile关键字对此变量进行说明。使用全局变量进行线程通信的方法非常简单,通过下面给出的示例代码能够对其有一个基本的认识。
  
   // 线程通信用全局变量
   volatile bool g_bDo = false;
   ……
   //线程处理函数
   UINT ThreadProc5(LPVOID pParam)
   {
   //根据全局变量g_bDo的取值来决定线程的运行
   while (g_bDo)
   {
   Sleep(2000);
   AfxMessageBox("线程正在运行!");
   }
  
   AfxMessageBox("线程终止");
   return 0;
   }
   ……
   void CSample06View::OnGlobalStart()
   {
   // 通过全局变量通知线程执行
   g_bDo = true;
  
   // 启动线程
   AfxBeginThread(ThreadProc5, NULL);
   }
   void CSample06View::OnGlobalEnd()
   {
   // 通过全局变量通知线程结束
   g_bDo = false;
   }
  
  2.利用自定义消息
   全局变量在线程通信中的应用多用在主线程对子线程的控制上,而从子线程向主线程的信息反馈则多采用自定义消息的方式来进行。这里对自定义消息的使用同使用普通自定义消息非常相似,只不过消息的发送是在子线程函数中进行的。该方法的主体是自定义消息,应首先定义自定义消息并添加对消息的响应代码。
  
   // 自定义消息
   #define WM_USER_MSG WM_USER + 101
   ……
   //消息响应函数在头文件中的定义:
   //{
{AFX_MSG(CSample06View)
   //}}AFX_MSG
   afx_msg void OnUserMsg(WPARAM wParam, LPARAM lParam);
   DECLARE_MESSAGE_MAP()
   ……
   //消息映射
   BEGIN_MESSAGE_MAP(CSample06View, CView)
   //{
{AFX_MSG_MAP(CSample06View)
   //}}AFX_MSG_MAP
   ON_MESSAGE(WM_USER_MSG, OnUserMsg)
   END_MESSAGE_MAP()
   ……
   //消息响应函数
   void CSample06View::OnUserMsg(WPARAM wParam, LPARAM lParam)
   {
   // 报告消息
   AfxMessageBox("线程已退出!");
   }
  
   此后,在子线程函数需要向主线程发送消息的地方调用PostMessage()或SendMessage()消息传递函数将消息发送给主线程即可。由于消息发送函数是在线程中被调用,因此需要指出接受窗口句柄,可通过线程参数将其传递进线程函数。
  
   UINT ThreadProc6(LPVOID pParam)
   {
   // 延迟一秒
   Sleep(1000);
  
   // 向主线程发送自定义消息
   ::PostMessage((HWND)pParam, WM_USER_MSG, 0, 0);
   return 0;
   }
   ……
   void CSample06View::OnUseMessage()
   {
   // 获取窗口句柄
   HWND hWnd = GetSafeHwnd();
  
   // 启动线程
   AfxBeginThread(ThreadProc6, hWnd);
   }
  
  3.使用事件内核对象
   利用事件(Event)内核对象对线程的通信要复杂些,主要通过对事件对象的监视来实现线程间的通信。事件对象由CreateEvent()函数来创建,具有两种存在状态:置位与复位,分别由SetEvent()和ResetEvent()来产生。事件的置位将通过WaitForSingleObject()或WaitForMultipleObjects()之类的通知等待函数继续执行。
  
  // 事件句柄
  HANDLE hEvent = NULL;
  
  UINT ThreadProc7(LPVOID pParam)
  {
   while(true)
   {
   // 等待事件发生
   DWORD dwRet = WaitForSingleObject(hEvent, 0);
   // 如果事件置位则退出线程,否则将继续执行
   if (dwRet == WAIT_OBJECT_0)
   break;
   else
   {
   Sleep(2000);
   AfxMessageBox("线程正在运行!");
   }
   }
  
   AfxMessageBox("线程终止运行!");
   return 0;
  }
  ……
  void CSample06View::OnEventStart()
  {
   // 创建事件
   hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  
   // 启动线程
   AfxBeginThread(ThreadProc7, NULL);
  }
  
  void CSample06View::OnEventEnd()
  {
   // 事件置位
   SetEvent(hEvent);
  }
  
   上面这段代码展示了事件对象在线程通信中的作用。在创建线程前首先创建一个事件对象hEvent,这里CreateEvent()函数所采用的四个参数分别表示句柄不能被继承、事件在置位后将由系统自动进行复位、事件对象初始状态为复位状态和不指定事件名。在创建的子线程中使用WaitForSingleObject()对hEvent进行监视。WaitForSingleObject()的函数原型为:
  
   DWORD WaitForSingleObject(
   HANDLE hHandle, //等待对象的句柄
   DWORD dwMilliseconds //超过时间间隔
   );
  
   函数将在hHandle对象有信号时或是在等待时间超出由dwMilliseconds设定的超时时间间隔返回。其返回值可以为WAIT_ABANDONED、WAIT_OBJECT_0和WAIT_TIMEOUT,分别表示被等待的互斥量(Mutex)对象没有被释放、等待的对象信号置位和超时。通过对返回值的判断可以区分出引起WaitForSingleObject()函数返回的原因。在本例中只关心WAIT_OBJECT_0的返回值,当通过SetEvent()将hEvent置位后即可使WaitForSingleObject()立即返回并通过跳出循环而结束线程。

转载地址:http://zhosi.baihongyu.com/

你可能感兴趣的文章
postgresql监控工具pgstatspack的安装及使用
查看>>
【JAVA数据结构】双向链表
查看>>
【JAVA数据结构】先进先出队列
查看>>
乘法逆元
查看>>
Objective-C 基础入门(一)
查看>>
Flutter Boost的router管理
查看>>
iOS开发支付集成之微信支付
查看>>
C++模板
查看>>
【C#】如何实现一个迭代器
查看>>
【C#】利用Conditional属性完成编译忽略
查看>>
DirectX11 光照演示示例Demo
查看>>
VUe+webpack构建单页router应用(一)
查看>>
Node.js-模块和包
查看>>
(python版)《剑指Offer》JZ01:二维数组中的查找
查看>>
管理用户状态——Cookie与Session
查看>>
Spring MVC中使用Thymeleaf模板引擎
查看>>
PHP 7 的五大新特性
查看>>
深入了解php底层机制
查看>>
PHP中的stdClass 【转】
查看>>
XHProf-php轻量级的性能分析工具
查看>>