Windows中多线程的基础知识——2事件对象

news2024/11/24 10:40:28

 上一节我们介绍了线程同步、以及利用互斥对象实现线程同步的方法。这一节,我们继续介绍另一种线程同步的方法:事件对象。如果对线程概念、互斥对象概念不清楚的同学,请查看Windows中多线程的基础知识——1互斥对象。

1 事件对象

1.1 事件对象概念

 事件对象也属于内核对象,它包含以下三个成员:
 1. 使用计数;
 2. 用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值;
 3. 用于指明该事件处于已通知状态还是未通知状态的布尔值。
 事件对象有两种不同的类型:人工重置的事件对象和自动重置的事件对象。当人工重置的事件对象得到通知时,等待该事件对象的所有线程均变为可调度线程。当一个自动重置的事件对象得到通知时,等待该事件对象的线程只有一个线程变为可调度对象。

1.2 事件对象相关函数

一、创建事件对象

 创建事件对象的函数原型为:

HANDLE WINAPI CreateEvent(
__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,
__in BOOL bManualReset,
__in BOOL bInitialState,
__in_opt LPCTSTR lpName
);

函数参数说明:
 lpEventAttributes: 一般为NULL;
 bManualReset:创建的Event是人工重置事件对象,还是自动重置事件对象。如果TRUE,表示该函数将创建一个人工重置对象;如果此参数为FALSE,为自动重置事件对象。如果是人工重置事件对象,当线程等待到该对象的所有权之后,需要调用ResetEvent函数手动的将事件对象设置为无信号状态;如果是自动重置对象,当线程等待该对象的所有权之后,系统会自动将对象设置为无信号状态。
 bInitialState:初始状态,true,有信号,false无信号
 lpName:事件对象的名称。
 该函数创建一个Event同步对象,如果CreateEvent调用成功的话,会返回新生成的对象的句柄,否则返回NULL。
 请注意,当人工重置的事件对象得到通知时,等待该事件对象的所有线程均变为可调度线程;当一个自动重置的事件对象得到通知时,等待该事件对象的线程中只有一个线程可变为可调度对象,同时操作系统会将该事件对象设置为无信号状态。
 MSDN的原文说明为:

When the state of a manual-reset event object is signaled, it remains signaled until it is explicitly reset to nonsignaled by the ResetEvent function. Any number of waiting threads, or threads that subsequently begin wait operations for the specified event object, can be released while the object’s state is signaled.
When the state of an auto-reset event object is signaled, it remains signaled until a single waiting thread is released; the system then automatically resets the state to nonsignaled. If no threads are waiting, the event object’s state remains signaled.

二、设置事件对象状态

 SetEvent函数将把指定的事件对象设置为有信号状态,函数原型为:

BOOL WINAPI SetEvent( __in HANDLE hEvent);

 其中的参数为将要设置其状态的事件对象的句柄。

三、重置事件对象状态

 ResetEvent函数将把指定的事件对象设置为无信号状态,函数原型为:

BOOL WINAPI ResetEvent( __in HANDLE hEvent);

2 利用事件对象实现线程同步的例程

#include <windows.h>
#include <iostream>

HANDLE g_hEvent;
int iTickets = 1000;

//线程1的入口函数
DWORD WINAPI Fun1Proc(__in  LPVOID lpParameter)
{
	while (true)
	{
		//请求事件对象
		WaitForSingleObject(g_hEvent, INFINITE);
		if (iTickets > 0)
		{
			std::cout << "thread1 sell tickes:" << iTickets-- << std::endl;
			SetEvent(g_hEvent);
		}
		else
		{
			SetEvent(g_hEvent);
			break;
		}
	}

	return 0;
}

//线程2的入口函数
DWORD WINAPI Fun2Proc(__in  LPVOID lpParameter)
{
	while (true)
	{
		//请求事件对象
		WaitForSingleObject(g_hEvent, INFINITE);
		if (iTickets > 0)
		{
			std::cout << "thread2 sell tickes:" << iTickets-- << std::endl;
			SetEvent(g_hEvent);
		}
		else
		{
			SetEvent(g_hEvent);
			break;
		}
	}

	return 0;
}

int main()
{
	HANDLE hThread1;
	HANDLE hThread2;

	//创建人工重置事件内核对象
	g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	//将事件设置为有信号状态
	SetEvent(g_hEvent);

	//创建线程
	hThread1 = CreateThread(NULL, 0, Fun1Proc, NULL, 0, NULL);
	hThread2 = CreateThread(NULL, 0, Fun2Proc, NULL, 0, NULL);
	CloseHandle(hThread1);
	CloseHandle(hThread2);

	//以下代码为了防止主线程提前退出,从而使进程退出,也就终止了进程下所有线程的运行
	while (true)
	{
		if (iTickets > 0)
			Sleep(200);
		else
		{
			//关闭事件对象句柄
			CloseHandle(g_hEvent);
			getchar();
			return 0;
		}
	}
}

 和上一节一样,以上代码也是在main中创建了两个线程(并且即刻执行),两个线程都会访问全局变量iTickets ,每卖一张票,就会将此全局变量递减1。为了实现线程同步,我们在main中创建了事件对象,并且设置事件对象为自动重置事件对象,且设置其处于有信号状态。在两个线程执行时,会请求这个事件对象,首先得到事件对象的线程得以继续执行,与此同时设置事件对象为无信号状态(因此,其他线程就得不到该事件对象,也就只能暂停等待),当执行完毕时,恢复事件对象为有信号状态。接下来,在系统调度下,两个线程会相继执行,无论哪个线程得到事件对象,都会暂停另一个线程的执行,这样,就实现了线程同步。
在这里插入图片描述

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

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

相关文章

SAP MM BP供应商主数据学习实践总结

一 常用Tcode 基于Tcode的顺序排列 供应商主数据物料主数据货源清单配额安排采购信息记录采购订单框架协议采购询价/报价采购申请订单收货发票校验物料需求计划BP-供应商主数据MM01 - 物料主数据新增ME01 - 维护MEQ1 - 维护ME11 - 创建ME21N - 创建框架协议-合同:询价:ME51…

LeetCode 133. Clone Graph【图,DFS,BFS,哈希表】中等

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

Tequila Works x Incredibuild

关于 Tequila Works Tequila Works 是一家位于西班牙马德里的电子游戏开发商&#xff0c;由劳尔鲁比奥 (Raul Rubio) 和卢兹桑乔 (Luz Sancho) 于2009年创立。该公司著名的游戏产品包括《死亡曙光》(Deadlight)、《霜华》(Rime)、《联盟外传&#xff1a;努努之歌》(Song of Nu…

革命性的电子元件:RAD继电器 | 百能云芯

在现代电子和通信系统中&#xff0c;RAD继电器是一种关键的电子元件&#xff0c;它在各种应用中发挥着重要作用。RAD继电器&#xff08;Reed-relay Actuated Device&#xff09;是一种基于磁性原理的电子开关&#xff0c;其特点是极其高速、可靠、低功耗和长寿命。下面云芯将为…

企业架构LNMP学习笔记12

1、Server配置&#xff1a; Server虚拟主机的配置&#xff1a; 在实际生产业务环境中&#xff0c;一台web服务器&#xff0c;需要使用多个网站部署。搭建vhost虚拟主机实现不同域名&#xff0c;解析绑定到不同的目录。 #基于http的web服务 server{#监听端口listen 80#配置虚…

2023年7月京东咖啡行业数据分析(京东数据报告)

瑞幸咖啡与贵州茅台推出的联名咖啡“酱香拿铁”正式上市&#xff0c;一度掀起消费者的消费浪潮。在此之前&#xff0c;瑞幸也与多个品牌推出过联名款咖啡&#xff0c;每次的热度都颇高&#xff0c;这在背后&#xff0c;除了有消费者的猎奇心理外&#xff0c;更重要的是&#xf…

生成与调用C++动态链接库(so文件)

文章目录 前言生成C动态链接库步骤1&#xff1a;编写C源码步骤2&#xff1a;生成共享库步骤3&#xff1a;验证生成的SO文件 调用C动态链接库步骤1&#xff1a;修改原来makefile步骤2&#xff1a;编译调用程序步骤3&#xff1a;运行调用程序 总结 前言 动态链接库是代码重用和模…

[移动通讯]【Carrier Aggregation in LTE】【 Log analysis-2】

前言&#xff1a; 接 [移动通讯]【Carrier Aggregation in LTE】【 Theory Log analysis-1】 这里面 主要讲解一下日志分析 目录&#xff1a; 总体流程 UE Capbaility Information MeasurementReport RRC Connection Reconfiguration RRCConnectionReconfiguration…

2D项目经验总结

2D项目经验总结 前言地图的绘制Sprite Editor叠层注意点&#xff08;SortingLayer相关知识点&#xff09;Tile Paltette的使用Animated Tiles&#xff08;动起来的图片&#xff08;也称作瓷片或者瓦砖&#xff09;&#xff09; 玩家移动玩家方向的翻转刚体注意点 碰撞器输入系统…

蓝桥杯打卡Day2

文章目录 糖果分享游戏玛雅人的密码 一、糖果分享游戏IO链接 本题思路:本题是一道模拟题&#xff0c;最终需要每个人得到相同的糖果&#xff0c;那么此时我们开辟一个数组用来保存每个人分一半的结果&#xff0c;然后每个人都需要从左边拿到对方糖果&#xff0c;那么左边就是…

软件测试案例 | “某气候中心数据加工处理系统”软件项目验收测试

近年来&#xff0c;随着软件行业技术和市场环境的变化&#xff0c;越来越多的企业选择将软件项目外包。在外包的软件项目日益增长的情况下&#xff0c;如何对这些外包的项目进行质量控制已成为许多企业的一个关键问题。在软件的众多质量控制手段中&#xff0c;验收测试是其中主…

whatsapp群发:如何应对封号问题

首先&#xff0c;需要明确一个观点&#xff0c;各大平台针对骚扰用户的行为都采取了严厉的打击措施。我们进行WhatsApp客户开发&#xff0c;这本身就属于一种被WhatsApp严厉打击的活动。账号可能会被临时封禁&#xff0c;甚至永久封禁&#xff0c;这是一种可能会发生的风险。因…

视频监控/安防监控EasyCVR平台智能边缘网关硬件ubuntu系统如何取消休眠?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频汇聚融合管理…

Gridea+GitPage+Gittalk 搭建个人博客

&#x1f44b;通过GrideaGitPage 搭建属于自己的博客&#xff01; &#x1f47b;GitPage 负责提供 Web 功能&#xff01; &#x1f63d;Gridea 作为本地编辑器&#xff0c;方便 push 文章&#xff01; &#x1f3f7;本文讲解如何使用 GrideaGitPage 服务域名&#xff08;可选&a…

U3D外包开发框架及特点

U3D&#xff08;Unity3D&#xff09;是一款流行的跨平台游戏开发引擎&#xff0c;用于创建2D和3D游戏以及交互性应用程序。U3D有许多常用的开发框架和库&#xff0c;这些框架和库可以扩展其功能&#xff0c;使开发人员更轻松地构建游戏和应用程序。以下是一些常用的U3D开发框架…

利用Python来实现动态吃月饼不过分吧!

前言&#xff1a; 中秋节是中国传统的重要节日之一&#xff0c;通常在农历八月十五这一天庆祝。这个节日是为了庆祝丰收和家庭团聚而设立的。中秋节的主要活动包括赏月、吃月饼、赏花灯和进行一些传统的民俗游戏。家人团聚在一起&#xff0c;分享月饼、拜月、赏月&#xff0c;是…

Android逆向学习(三)vscode修改smali绕过vip

Android逆向学习&#xff08;三&#xff09;vscode修改smali绕过vip 写在前面 这是吾爱的第二个作业&#xff0c;主要就是要修改smali代码&#xff0c;其实smali代码我感觉没有必要去学&#xff0c;当然主要是我本来就会汇编语言&#xff0c;基本上汇编语言都是一样的&#x…

附录3-爬取58二手房信息,爬取4k图片案例,爬取城市名称,爬取站长素材简历模板(xpath使用案例)

目录 1 爬取58二手房信息 1.1 分析 1.2 代码 2 爬取4k图片案例 2.1 分析 2.2 代码 3 爬取城市名称案例 3.1 分析 3.2 代码 4 爬取站长素材简历模板 4.1 分析 4.2 代码 1 爬取58二手房信息 地址 请输入验证码 ws:121.36.42.44 1.1 分析 我需要标题…

朔雪流量复制器的前端

朔雪流量复制器的前端 1. 功能需求简介 本流量复制器使用端口映射模式实现流量复制&#xff0c;可以实现一对一&#xff0c;一对多&#xff0c;和多对一的流量复制模式。 映射网口的多少取决于设备的硬件&#xff0c;最多可以支持36端口。 使用模式包括** 1&#xff09;从1…

【日积月累】Java开发习惯养成

目录 Java开发习惯养成 1.前言2.equals()的使用3.整形包装类型的使用BigDecimalBigDecimal大小比较BigDecimal 保留几位小数BigDecimal注意事项 基本数据类型与包装数据类型的使用标准数组与List之间的转换的坑数组转List数组转ArrayLIstList转数组 反转数组 总结参考 文章所…