WaitForSingleObject 函数的诸多用途与使用场景总结

news2024/11/17 21:54:56

目录

1、WaitForSingleObject函数详细说明

2、在线程函数中调用WaitForSingleObject实现Sleep,可立即退出Sleep状态

3、调用WaitForSingleObject函数监测线程或进程是否已经退出

3.1、子进程实时监测主进程是否已经退出,主进程退出了,则子进程要自动退出

3.2、启动子进程后等待子进程执行完退出后,再执行后续操作


C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_2276111.html       在做多线程同步时,我们经常调用WaitForSingleObject接口去等待事件、互斥量和信号量等对象,获取这些对象的所有权。除了等待这些对象的作用外,还可以去等待线程和进程,今天就来结合日常的代码实践,详细地总结一下WaitForSingleObject函数的用途。

1、WaitForSingleObject函数详细说明

       WaitForSingleObject 函数检查指定对象的当前状态。 如果对象的状态未对齐,则调用线程将进入等待状态,直到发出对象信号或超时间隔已过。

DWORD WaitForSingleObject( [in] HANDLE hHandle, [in] DWORD  dwMilliseconds );

此函数的参数说明说下:

[in] hHandle
要等待的对象句柄。 WaitForSingleObject 函数可以等待以下对象:

  • 更改通知
  • 控制台输入
  • 可等待计时器
  • 内存资源通知
  • 事件(Event)
  • 互斥量(Mutex)
  • 信号量(Semaphore)
  • 线程(Thread)
  • 进程(Process)

句柄必须具有 SYNCHRONIZE 访问权限,SYNCHRONIZE的说明如下:

The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state.

[in] dwMilliseconds
超时间隔(以毫秒为单位)。 如果指定了非零值,则函数将等待,直到发出对象信号或间隔已过。 如果 dwMilliseconds 为零,则如果未向对象发出信号,则函数不会进入等待状态;它始终立即返回。 如果 dwMilliseconds 为 INFINITE,则函数仅在发出对象信号时返回。

关于WaitForSingleObject函数的说明,可以查看微软MSDN上的说明:

​​​​​​WaitForSingleObjecticon-default.png?t=N7T8https://learn.microsoft.com/zh-cn/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject        WaitForSingleObject 函数可以等待以下对象:

  • 更改通知
  • 控制台输入
  • 可等待计时器
  • 内存资源通知
  • 事件(Event)
  • 互斥量(Mutex)
  • 信号量(Semaphore)
  • 线程
  • 进程

对于事件,分有信号和无信号两个状态,当事件对象编程有信号时,WaitForSingleObject立即返回。

       对于互斥量和信号量,调用WaitForSingleObject获取所有权,即WaitForSingleObject返回WAIT_OBJECT_0时获取他们的所有权,然后调用ReleaseMutex和ReleaseSemaphore释放对象的所有权。

       对于线程和进程,线程和进程创建时无信号,当线程和进程退出时对应的句柄就变成了有信号,这样WaitForSingleObject就返回了。可以通过WaitForSingleObject返回,判断线程或进程是否已经退出了:

WaitForSingleObject(hThread, INFINITE); // 参数INFINITE表示无限等待

        在这里,给大家重点推荐一下我的几个热门畅销专栏:

专栏1:(该专栏订阅量接近350个,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!)

C++软件调试与异常排查从入门到精通系列文章汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据近几年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的实战问题分析实例,带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

专栏中的文章均是通过项目实战总结出来的(通过项目实战积累了大量的异常排查素材和案例),有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2: 

C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域的多个方面的内容,同时给出C/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!

专栏3: 

开源组件及数据库技术icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html

以多年的开发实战为基础,分享一些开源组件及数据库技术! 


2、在线程函数中调用WaitForSingleObject实现Sleep,可立即退出Sleep状态

       一般在线程的线程函数中设置一个循环,在循环体中循环往复的执行相关的业务,但不能让循环体中的代码中不停歇地执行,否则线程会占用大量的CPU时间片,会导致程序的高CPU占用问题。

当程序出现高CPU占用问题时,基本都是程序中发生死循环了,所在线程一直在不停歇地执行,占用了大量的CPU时间片,所以导致线程占用了较高的CPU比例。

       所以,我们一般都要在线程函数的循环体中人为地添加一个Sleep,让线程时不时休息一下,不要那么忙碌。当线程进入Sleep状态时,线程就被挂起了,线程停止执行,系统不再给线程分配CPU时间片,当Sleep时间到了后,系统再唤醒线程,给线程分配CPU时间片,线程得以继续执行。

       实现线程Sleep有两种方式,一种是直接调用C函数Sleep睡眠,另一种借助事件对象去实现Sleep。使用事件实现有个好处是,能立即结束睡眠,退出Sleep状态。比如在终止线程执行时,能让Sleep立即停止,线程函数中的循环尽快结束,线程函数尽快退出。

       下面举一个使用事件对象实现Sleep的例子,我们在项目中多次使用了。先调用CreateEvent创建一个初始无信号,手动的事件对象:

// 创建一个手动的、初始无信号的事件对象
HANDLE hEvent = ::CreateEvent( NULL, TRUE, FALSE, NULL );

然后在创建线程时,将事件对象传到线程函数中:

// 创建一个线程去处理事务
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (void *)hEvent, 0, NULL);
if (hThread != NULL)
{
    CloseHandle( hThread );
}

        在线程函数ThreadFunc中,获取到传入的事件对象参数,调用WaitForSingleObject函数实现Sleep(通过WaitForSingleObject等待超时实现Sleep):

unsigned _stdcall ThreadFunc(void *pParam)
{
    HANDLE hEvent = (HANDLE)pParam;

    BOOL bStart = TRUE;
    while (bStart)
    {
        // ...  // 此处的业务代码省略

        // 在循环体中调用WaitForSingleObject实现Sleep的效果
        ::WaitForSingleObject(hEvent, 500); // 通过等待超时,实现Sleep
    }

    return 1;
}

调用WaitForSingleObject进入等待状态时,会将线程挂起,这个Sleep的效果是一样的!

       最后在需要立即退出Sleep时,调用SetEvent函数将事件置为有信号,WaitForSingleObject立即返回。这样循环体就能尽快退出,线程函数能尽快退出,线程函数退出了,线程就结束了。

// 调用SetEvent将事件对象置为有信号,让WaitForSingleObject函数立即返回,尽快退出循环
::SetEvent(hEvent);

3、调用WaitForSingleObject函数监测线程或进程是否已经退出

       在主程序运行的过程中启动了一个子进程,有时主进程要等待子进程处理结果后根据返回的信息再控制后续代码的执行,有时子进程需要感知主进程是否已经退出,这两种情况都需要感知另一个进程是否已经退出。对于线程在某些场合下页存在类似的需求。

3.1、子进程实时监测主进程是否已经退出,主进程退出了,则子进程要自动退出

       主进程在运行过程中启动了一个子进程,启动子进程时将主进程的进程id传给子进程。子进程是依赖于主进程存活的,如果主进程退出或者崩溃了,则子进程就没有存在的意义了,要自动退出!所以子进程要实时监测主进程的状态,监测主进程有没有退出(包括崩溃闪退)。

       可能有人会说,主进程可以在退出时通知子进程,子进程收到通知后再自行退出。但主进程可能会发生崩溃或闪退,这种情况下一般时没法通知子进程的。

        那子进程如何才能实时监测主进程是否退出了呢?不管是主进程正常退出,还是异常崩溃闪退,都要感知到。子进程可以启动一个子线程,在子线程中通过主进程传过来的主进程id,获取主进程句柄,然后调用WaitForSingleObject等待主进程退出,可以在子线程中无限等待。如果主进程一旦退出,WaitForSingleObject函数就会立即返回,这时子进程就可以调用ExitProcess等接口自行退出当前子进程了。

       具体的代码实现是,子进程中启动一个子线程,将主进程传过来的主进程id传给该子线程,如下:(其中MonitorMainProcess是线程函数)

HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, MonitorMainProcess, (void*)dwMainProcessId, 0, NULL );
if ( hThread != NULL )
{
    CloseHandle( hThread );
}

线程函数MonitorMainProcess实现如下:

// 监控主工程
unsigned __stdcall MonitorMainProcess(void * pParam )
{
    DWORD dwProcessId = (DWORD)pParam;
    HANDLE hProcess = OpenProcess( SYNCHRONIZE, FALSE, dwProcessId );
    if(hProcess == NULL)
    {
        ExitProcess(-1);
    }
 
    // 设置INFINITE无限等待
    WaitForSingleObject( hProcess, INFINITE );
    CloseHandle( hProcess );
 
    // WaitForSingleObject返回了,就表示主进程已经退出,直接退出本进程
    ExitProcess( -1 );
}

       进程初始是无信号的,进程退出时就变成了有信号,这样WaitForSingleObject等待到信号后,就返回了,这样子进程就直到主进程退出了。

       此处需要注意一下,调用OpenProcess时必须要设置SYNCHRONIZE参数,因为设置该标记参数后才能调用WaitForSingleObject去等待进程。微软MSDN上对SYNCHRONIZE如下:

SYNCHRONIZE:The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state.

       此外,监测主进程是否退出的代码是阻塞式的,不能放在主线程中的,这就是为什么要启动一个子线程去专门做这个监测任务的原因。

3.2、启动子进程后等待子进程执行完退出后,再执行后续操作

       有时我们需要启动一个子进程去完成某项操作,主进程在等待子进程的执行结果(需要获取子进程的执行数据), 然后主进程再去执行后续操作。主进程在启动子进程后,就可以调用WaitForSingleObject等待子进程退出,比如如下的代码:

// 启动一个子进程去执行一个操作任务
STARTUPINFO s  = {sizeof(s)}; 
PROCESS_INFORMATION   pi = {0};   
if( CreateProcess( NULL, cmdLine, NULL, NULL, TRUE, NULL, NULL, NULL, &s, &pi ) )
{   
    // 等待进程执行完毕   
    WaitForSingleObject( pi.hProcess, INFINITE );   
 
    // 关闭进程和主线程句柄
    CloseHandle( pi.hProcess );   
    CloseHandle( pi.hThread );   
}  
 
// ...  // 去拿子进程的执行结果,去执行后续操作

       有时启动一个子线程,要等子线程执行完退出后,根据处理结果信息去继续执行,和上面等待进程退出是类似的。

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

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

相关文章

高级分布式系统-第15讲 分布式机器学习--神经网络理论

神经网络理论 模糊控制在处理数值数据、自学习能力等方面还远没有达到人脑的境界。人工神经网络从另一个角度出发,即从人脑的生理学和心理学着手,通过人工模拟人脑的工作机理来实现机器的部分智能行为。 人工神经网络(简称神经网络&#xf…

【嘉立创EDA】原理图显示/隐藏引脚标识

文章路标👉 文章解决问题主题内容be end..文章解决问题 1️⃣ 嘉立创EDA专业版,操作版本是V2.1.17客户端半离线版本。 本文基于嘉立创EDA专业版讲述如何将原理图中已建立的器件的引脚标识进行显示或隐藏。本文将此过程记录,以供有需要的读者参考。 主题内容 2️⃣ 对目…

html5+css3+bootstrap+js 新闻网页

新闻网页练习打卡! 一、首页 二、社会 三、财经 四、视频展示 简易新闻网站(期末作业)

无纸化革新:纸质文件转在线存储和检索 | 开源日报 No.141

paperless-ngx/paperless-ngx Stars: 13.9k License: GPL-3.0 Paperless-ngx 是一个文档管理系统,将您的纸质文件转换为可搜索的在线存档,以便您可以保留更少的纸张。 完整功能列表和截图可在文档中找到通过 docker compose 最简单地部署 paperless可以…

Linux驱动学习—IIC总线之FT5X06触摸驱动实验

1、实现触摸坐标值上报 流程图&#xff1a; 设备树如下&#xff1a; 触摸设备对应的设备树节点是&#xff1a; 读取坐标的寄存器&#xff1a; #include <linux/init.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/gpio.h> #i…

HTML---JAVAscript对向和原型链

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 一.JavaSceipt对象概述 JavaScript是一种基于对象的编程语言&#xff0c;每个值都是一个对象。JavaScript中的对象是一种无序的键值对集合&#xff0c;其中每个键都是唯一的。 JavaScript的…

@Controller层自定义注解拦截request请求校验

一、背景 笔者工作中遇到一个需求&#xff0c;需要开发一个注解&#xff0c;放在controller层的类或者方法上&#xff0c;用以校验请求参数中(不管是url还是body体内&#xff0c;都要检查&#xff0c;有token参数&#xff0c;且符合校验规则就放行)是否传了一个token的参数&am…

D4140 交流插座电器漏电断路器的低功耗控制芯片,内置桥式整流器漏电灵敏度可调,采用SOP8和DIP8 的封装形式

D4140 是一种用于交流插座电器漏电断路器的低功耗控制器。这些设备可以检测到接地的危险电流路径&#xff0c;例如设备掉进水中。在发生有害或致命的电击之前&#xff0c;断路器会断开线路。内置有整流桥&#xff0c;齐纳管稳压器&#xff0c;运算放大器&#xff0c;电流基准&a…

C++(11)——string

前面通过前面篇文章介绍了中的各项基本知识。从本篇文章开始&#xff0c;将对中的中的各项内容进行介绍&#xff1a; 目录 1.string类对象的常见构造&#xff1a; 2. string类对象的赋值操作&#xff1a; 3. string类对象的访问与遍历&#xff1a; 3.1 string类对象的访问…

大数据Doris(五十六):SQL函数之地理位置函数

文章目录 SQL函数之地理位置函数 一、​​​​​​​ST_AsText(GEOMETRY geo)

An efficient path-based approach for influence maximization in social networks

ABSTRACT 口碑对社会联系的影响非常强大&#xff0c;这已不是什么秘密&#xff0c;但问题是“哪些因素影响口碑的有效性&#xff1f;”答案取决于一小组节点如果被激活&#xff0c;就会将信息传播到整个网络。这是社交网络分析中的一个主要问题&#xff0c;称为影响力最大化&am…

优雅处理并发:Java CompletableFuture最佳实践

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff0c;今天&#xff0c;小黑要和大家聊聊CompletableFuture&#xff0c;这个Java 8引入的强大工具。 在Java传统的Future模式里&#xff0c;咱们都知道&#xff0c;一旦开始了一个异步操作&#xff0c;就只能等它结束…

Xcode 15 for Mac:超越开发的全新起点

作为一名开发人员&#xff0c;你是否正在寻找一款强大而高效的开发工具&#xff0c;来帮助你在Mac上构建出卓越的应用程序&#xff1f;那么&#xff0c;Xcode 15就是你一直在寻找的答案。 Xcode 15是苹果公司最新推出的一款集成开发环境&#xff08;IDE&#xff09;&#xff0…

介绍C++的关键字(保留字)

介绍C的关键字&#xff08;保留字&#xff09; 1. asm asm (指令字符串)&#xff1a;允许在 C 程序中嵌入汇编代码。 2. auto auto&#xff08;自动&#xff0c;automatic&#xff09;是存储类型标识符&#xff0c;表明变量"自动"具有本地范围&#xff0c;块范围的…

2024PMP考试新考纲-【过程领域】近期典型真题和很详细解析(6)

距离2024年3月10日的PMP考试还有不到两个月了&#xff0c;加油&#xff01; 华研荟继续为您分享【过程Process领域】的新考纲下的真题&#xff0c;进一步帮助大家体会和理解新考纲下PMP的考试特点和如何应用知识来解题&#xff0c;并且举一反三&#xff0c;一次性、高等级通过…

【excel密码】Excel中如何使部分单元格区域实现加密

Excel文件可以设置保护工作表&#xff0c;那么可以只保护工作表中的部分单元格&#xff0c;其他地方可以正常编辑吗&#xff1f;当然是可以的&#xff0c;今天我们学习&#xff0c;如何设置保护部分单元格。 首先&#xff0c;我们先将整张工作表选中&#xff08;Ctrl A&#…

不会写诗怎么办?收藏好,让你分分钟变成大才子

大家都知道&#xff0c;诗有五种载体&#xff0c;分别是五言绝句&#xff0c;五言律诗&#xff0c;七言绝句&#xff0c;七言律诗&#xff0c;以及排律。言指的是每句的字数&#xff0c;绝句是四句&#xff0c;律诗是八句&#xff0c;排律不限句数。 首先&#xff0c;我们先说…

【实施】windows部署OA项目

文章目录 一、安装JDK1.1 下载安装包后&#xff0c;傻瓜式安装即可1.2 配置环境变量1.3 测试 二、配置Tomcat2.1 关闭防火墙2.2 下载安装包后&#xff0c;在bin下双击startup启动tomcat2.3 防火墙配置 &#xff08;开放8080端口 三、MySQL安装四、部署OA项目4.1 导入数据库4.2 …

创健医疗:接棒玻尿酸,重组胶原蛋白也要迎来股市“三剑客”?

从锦波生物北交所上市后最高溢价5.17倍、鸿星尔克跨界布局重组胶原蛋白领域、首届重组胶原蛋白技术峰会召开&#xff0c;到巴黎欧莱雅新添重组胶原蛋白成分新品——小蜜罐第二代面霜的首发成功&#xff0c;再到位列重组胶原蛋白行业第一阶梯的创健医疗完成辅导备案登记&#xf…

Windows 下 QT开发环境的搭建:

下载QT:Index of /archive/qt/5.14 下载Cmake :CMake - Upgrade Your Software Build System (1)QT在windows,C, 打包exe&#xff1a; step1:window上安装QT软件&#xff1a; Windows下的QT系统开发环境搭建_qt windows-CSDN博客. step2:新建一个界面工程&#xff1a; (1)打…