事件EVENT,WaitForSingleObject(),WaitForMultipleObjecct()和SignalObjectAndWait() 的使用(上)

用户模式的线程同步机制效率高,如果需要考虑线程同步问题,应该首先考虑用户模式的线程同步方法。但是,用户模式的线程同步有限制,对于多个进程之间的线程同步,用户模式的线程同步方法无能为力。这时,只能考虑使用内核模式。

Windows提供了许多内核对象来实现线程的同步。对于线程同步而言,这些内核对象有两个非常重要的状态:“已通知”状态,“未通知”状态(也有翻译为:受信状态,未受信状态)。Windows提供了几种内核对象可以处于已通知状态和未通知状态:进程、线程、作业、文件、控制台输入/输出/错误流、事件、等待定时器、信号量、互斥对象。


与事件EVENT的配合使用,能够解决很多同步问题,也可以在数据达到某个状态时启动另一个线程的执行,如报警。

EVENT 的几个函数:

1、CreateEvent和OpenEvent

HANDLE WINAPI CreateEvent(__in          LPSECURITY_ATTRIBUTES lpEventAttributes,    //表示安全控制,一般直接传入NULL,表示不能被子进程继承__in          BOOL bManualReset,  //参数确定事件是手动置位还是自动置位,传入TRUE表示手动置位,传入FALSE表示自动置位。__in          BOOL bInitialState,  //Event的初始状态, TRUE为触发,FALSE未触发__in          LPCTSTR lpName   //Event object的名字,NULL表示没名字(without a name)
);
要是CreateEvent创建的事件没名字  这个函数就没啥用了,不多做介绍,可查看msn。
HANDLE WINAPI OpenEvent(                   //获得已经存在的Event的事件句柄__in          DWORD dwDesiredAccess,__in          BOOL bInheritHandle,__in          LPCTSTR lpName       //要打开的事件名字
);

2、SetEvent,触发事件

BOOL SetEvent(HANDLE hEvent);

3、ResetEvent,使事件状态设为未触发,如在创建事件时第二个参数为TRUE手动设置,则需要该函数去恢复事件为未触发状态。

BOOL SetEvent(HANDLE hEvent);

4、PulseEvent, 如在创建事件时第二个参数为TRUE手动设置,其功能相当于SetEvent()后立即调用ResetEvent(),最好别用

BOOL PulseEvent(HANDLE hEvent)

5、CloseHandle(),关闭该句柄。

事件是内核对象,事件分为手动置位事件和自动置位事件。事件Event内部它包含一个使用计数(所有内核对象都有),一个布尔值表示是手动置位事件还是自动置位事件,另一个布尔值用来表示事件有无触发。事件可以由SetEvent()来触发,由ResetEvent()来设成未触发。还可以由PulseEvent()来发出一个事件脉冲。


WaitForSingleObject()

在多线程下面,有时候我们会希望等待某一线程完成了再继续做其他事情,要实现这个目的,可以使用Windows API函数WaitForSingleObject,或者WaitForMultipleObjects。这两个函数都会等待Object被标为有信号(signaled)时才返回的。
那么,什么是信号呢?
简单来说,Windows下创建的Object都会被赋予一个状态量。如果Object被激活了,或者正在使用,那么该Object就是无信号,也就是不可用;另一方面,如果Object可用了,那么它就恢复有信号了。

这两个函数的优点是它们在等待的过程中会进入一个非常高效沉睡状态,只占用极少的CPU时间片。(这两个函数都是在内核状态下等待内核对象,不切换到用户模式下,因而效率很高)

1、格式

DWORD WaitForSingleObject( HANDLE hHandle, DWORDdwMilliseconds);

有两个参数,分别是THandle和Timeout(毫秒单位)。

如果想要等待一条线程,那么你需要指定线程的Handle,以及相应的Timeout时间。当然,如果你想无限等待下去,Timeout参数可以指定系统常量INFINITE。

WaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到WaitForSingleObject有返回值才执行后面的代码。此外,当dwMilliseconds设置为特殊值0时,测试hHandle核心对象是否被激发,函数立即返回。

2. 使用对象
它可以等待如下几种类型的对象:

Event(事件),Mutex(互斥量),Semaphore(信号量),Process(进程),Thread(线程),Change notification(变更通知),Console input(控制台输入),Job(可以被理解为进程的容器),Memory resource notification(内存资源通知),Waitable timer(等待定时器)

3. 返回类型
WAIT_ABANDONED:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。

WAIT_OBJECT_0:核心对象已被激活WAIT_TIMEOUT:等待超时WAIT_FAILED:出现错误,可通过GetLastError得到错误代码

4.示例:

#include <windows.h>  
#include <stdio.h>  
#include <iostream.h>  //声明函数  创建线程  
DWORD WINAPI FunProc( LPVOID lpParameter);   void main()  
{  HANDLE hThread;  hThread=CreateThread(NULL,0,FunProc,NULL,0,NULL);  DWORD dwRet=WaitForSingleObject(hThread, 1);  if(dwRet==WAIT_OBJECT_0)  {  printf("创建的线程执行结束\n");  }  if(dwRet==WAIT_TIMEOUT)  {  printf("等待超时\n");  }  if(dwRet==WAIT_ABANDONED)  {  printf("Abandoned\n");  }  CloseHandle(hThread);  
}  DWORD WINAPI FunProc( LPVOID lpParameter )  
{     int i=1;  for(; i<1000; i++)  {  printf("%d  ", i);  if(! (i%10))  printf("\n");  }  return 0;  
}

注意:不可以在WaitForSingleObject()之前执行CloseHandle()否则会导致程序出错!!
官方文档解释:
这里写图片描述
如果在wait操作仍处于暂挂状态时关闭此句柄,则函数的行为将不明确。


WaitForMultipleObjecct()

WaitForMultipleObjects是Windows中的一个功能非常强大的函数,几乎可以等待Windows中的所有的内核对象

函数原型为:

DWORD WaitForMultipleObjects(  DWORD nCount,             // number of handles in the handle array  CONST HANDLE *lpHandles,  // pointer to the object-handle array  BOOL fWaitAll,            // wait flag  DWORD dwMilliseconds      // time-out interval in milliseconds  );  

参数解析:

  • DWORD 就是 Double Word, 每个word为2个字节的长度,DWORD双字即为4个字节,每个字节是8位。
  • nCount 指定列表中的句柄数量 最大值为MAXIMUM_WAIT_OBJECTS(64)

  • *lpHandles 句柄数组的指针。lpHandles为指定对象句柄组合中的第一个元素 HANDLE类型可以为(EventMutexProcessThreadSemaphore)数组

  • bWaitAll 等待的类型,如果为TRUE,表示除非对象都发出信号,否则就一直等待下去;如果FALSE,表示任何对象发出信号即可
  • dwMilliseconds指定要等候的毫秒数。如设为零,表示立即返回。如指定常数INFINITE,则可根据实际情况无限等待下去

函数的返回值有:

  • WAIT_ABANDONED_0:所有对象都发出消息,而且其中有一个或多个属于互斥体(一旦拥有它们的进程中止,就会发出信号)
  • WAIT_TIMEOUT:对象保持未发信号的状态,但规定的等待超时时间已经超过
  • WAIT_OBJECT_0:所有对象都发出信号
  • WAIT_IO_COMPLETION:(仅适用于WaitForMultipleObjectsEx)由于一个I/O完成操作已作好准备执行,所以造成了函数的返回
  • 返回WAIT_FAILED则表示函数执行失败,会设置GetLastError

bWaitAllFALSE,那么返回结果相似,只是可能还会返回相对于WAIT_ABANDONED_0WAIT_OBJECT_0的一个正偏移量,指出哪个对象是被抛弃还是发出信号。

WAIT_OBJECT_0是微软定义的一个宏,你就把它看成一个数字就可以了。

例如,WAIT_OBJECT_0 + 5的返回结果意味着列表中的第5个对象发出了信号

如果程序中的nObjectWaitWAIT_OBJECT_0 + 5

int nIndex = nObjectWait - WAIT_OBJECT_0;就是说nIndex =5也就表示第5个对象发出了信号

示例:
当 bWaitAll参数为FALSE可以等待其中之一的事件

HANDLE m_hEvent[2];    //两事件  m_hEvent[0]=CreateEvent(NULL, FALSE, FALSE, NULL);  
m_hEvent[1]=CreateEvent(NULL, FALSE, FALSE, NULL);  
CreateThread(NULL, 0, MyThreadProc, this, 0, NULL);  
DWORD WINAPI MyThreadProc(LPVOID lpParam)  
{   
while(TRUE)  {  //每次等500毫秒   int nIndex = WaitForMultipleObjects(2, pThis->m_hEvent, FALSE,500);     if (nIndex == WAIT_OBJECT_0 + 1)   {  //第二个事件发生   //ExitThread(0);   //break;    
}   else if (nIndex == WAIT_OBJECT_0) //第一个事件发生    
{   //第一个事件  }    
else if (nIndex == WAIT_TIMEOUT) //超时500毫秒    
{   //超时可作定时用    
}   
}  OutputDebugString("线程结束. /n");  return 0L;} 

当要处理第一个事件时,你只需执行SetEvent(m_hEvent[0]); 即可进入第一个事件的位置

当要执行第二个事件时执行SetEvent(m_hEvent[1]);

当 bWaitAll参数为TRUE等待所有的事件

DWORD WINAPI MyThreadProc(LPVOID lpParam)  
{ while(TRUE)  {  //每次等500毫秒    
int nIndex = WaitForMultipleObjects(2, pThis->m_hEvent, TRUE,500);     if (WAIT_OBJECT_0 + 1<= nIndex <= WAIT_OBJECT_0) //所有事件发生   {   //所有的信号量都有效时(事件都发生)其中之一无效。   }  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/448259.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

axios 中文文档、使用说明

以下内容全文转自 Axios 文档&#xff1a;https://www.kancloud.cn/yunye/axios/234845 ##Axios Axios 是一个基于 promise 的 HTTP 库&#xff0c;可以用在浏览器和 node.js 中。 Features 从浏览器中创建 XMLHttpRequests从 node.js 创建 http 请求支持 Promise API拦截请…

汽车熄火是什么原因?

汽车熄火是什么原因&#xff1f; 近来看见很多车主被车子熄火所困扰&#xff0c;驾校一点通帮助您从以下也许可以找出原因。 1、自动档车型&#xff1a; 自动档的车型不会轻易出现熄火的现象&#xff0c;而手动档的车型由于驾驶水平不高&#xff0c;可能会经常出现熄火的现象。…

数据库 -- 02

引擎介绍 1.什么是引擎 MySQL中的数据用各种不同的技术存储在文件&#xff08;或者内存&#xff09;中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术&…

事件EVENT,WaitForSingleObject(),WaitForMultipleObjecct()和SignalObjectAndWait() 的使用(下)

注意&#xff1a;当WaitForMultipleObjects等待多个内核对象的时候&#xff0c;如果它的bWaitAll 参数设置为false。其返回值减去WAIT_OBJECT_0 就是参数lpHandles数组的序号。如果同时有多个内核对象被触发&#xff0c;这个函数返回的只是其中序号最小的那个。 如果bWaitAll …

设置 shell 脚本中 echo 显示内容带颜色

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 shell脚本中echo显示内容带颜色显示,echo显示带颜色&#xff0c;需要使用参数 -e 格式如下&#xff1a; echo -e "\033[字背景颜…

Visual C++ 编译器选项 /MD、/ML、/MT、/LD

前段时间编译一个引用自己写的静态库的程序时老是出现链接时的多个重定义的错误&#xff0c;而自己的代码明明没有重定义这些东西&#xff0c;譬如&#xff1a; LIBCMT.lib(_file.obj) : error LNK2005: ___initstdio already defined in libc.lib(_file.obj) LIBCMT.lib(_fi…

Delphi面向对象编程的20条规则

Delphi面向对象编程的20条规则 作者简介 Marco Cantu是一个知名的Delphi专家&#xff0c;他曾出版过《精通Delphi》系列丛书&#xff0c;《Delphi开发手册》以及电子书《精通Pascal》(该电子书可在网上免费获得)。他讲授的课题是Delphi基础和高级开发技巧。你可以通过他…

制动失灵怎么办?

定义 制动过程中&#xff0c;由于制动器某些零部件的损坏或发生故障&#xff0c;使运动部件(或运动机械)不能保持停止状态或不能按要求停止运动的现象。 制动失灵的原因 制动失灵的关键在于制动系统无法对汽车施加足够的制动力&#xff0c;包括制动液管路液位不足或进入空气、制…

OpenDDS用idl生成自定义数据类型时遇到的一个问题

问题&#xff1a;这里会提示LNK2005重复定义的错误 解决方案&#xff1a; 解决后&#xff1a;

解决:Connect to xx.xx.xxx.xx :8081 [/xx.xx.xx.xx] failed: Connection refu sed: connect -> [H

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 自行启动了个 Nenux 服务。想把本地工程推送到 个人私服&#xff0c;执行命令&#xff1a;mvn deploy 报错&#xff1a; Failed to…

ADOQuery 查询 删除 修改 插入

//利用combobox组件查询数据库表procedure TForm1.Button1Click(Sender: TObject);beginADOQuery1.Close;ADOQuery1.SQL.Clear;ADOQuery1.SQL.Add(select * from trim(ComboBox2.Text));ADOQuery1.Active:true;end&#xff1b; //查询记录procedure TForm1.Button1Click(Sender…

防爆胎,有妙招

对于大多数人来说&#xff0c;买车难,养车更难。许多人拥有了新车&#xff0c;却没有足够的知识去好好保养汽车&#xff0c;这实在是非常可惜。如何做好汽车的保养工作,让我们的爱车更好的为我们工作&#xff1f;夏天炽热的天气&#xff0c;是否让你为爆胎烦恼不已&#xff1f;…

Qt之QProcess(一)运行cmd命令

Qt提供了QProcess类&#xff0c;QProcess可用于完毕启动外部程序&#xff0c;并与之交互通信。 一、启动外部程序的两种方式&#xff1a; &#xff08;1&#xff09;一体式&#xff1a;void QProcess::start(const QString & program, const QStringList & arguments…

Docker 方式安装 Nexus 私服

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 从Docker 官方仓库查找镜像&#xff1a; docker search nexus 2. 拉取镜像&#xff1a; docker pull 你选中的镜像的名字  pull…

shader飞线改进版

项目github地址&#xff1a;https://github.com/ecojust/flyline 前面写过一个飞线(基于THREE.Line进行的颜色变化)&#xff0c;只是简单地将可视区片元颜色的alpha通道值设为1.0&#xff0c;不在可视区的设为0.0。效果是这样的&#xff1a; 做得很粗糙&#xff0c;而且因为线是…

转向盘失控怎么办?

定义 转向失控就是方向盘不管用了&#xff0c;打方向盘&#xff0c;但是前轮不动&#xff0c;不受方向盘控制。 转向失控的原因 转向失控可能因为车辆过快、酒驾、疲劳、车况不佳、雨雪路滑等&#xff0c;还有转向机构中有零部件脱落、损坏、卡滞时&#xff0c;也会使转向机构突…

Socket网络编程【获取本机IP】

//12.3.2//运行环境VS2013//获取本地IP #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib")void main() { // 调用WSAStarup初始化WINsock库 WSADATA wsaData; ::WSAStartup( MAKEWORD(2,2), &wsaData);// 存放主机名的…

onresize

1 window.onresize function (ev) { 2 console.log(尺寸发生改变&#xff01;); 3 }; 4 5 window.addEventListener(resize, function (ev) { 6 console.log(尺寸发生改变&#xff01;); 7 }); 1 /*2 当屏幕的宽度>960时&#xff0c;页面的背景颜色为红色…

Vuejs:组件 slot 内容分发

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 本文是在官方文档的基础上&#xff0c;更加细致的说明&#xff0c;代码更多更全。 简单来说&#xff0c;更适合新手阅读 &#xff08;…

C++获取本机所有ip地址,可区分类型是有线无线虚拟机还是回环

一个小程序&#xff0c;可以获取本地所有ip地址&#xff0c;包括有线&#xff0c;无线&#xff0c;虚拟机&#xff0c;环回接口网卡&#xff0c;等。 如图&#xff0c;一台机器多个网卡&#xff1a; 程序执行结果&#xff1a; #include"stdio.h" #include"…