Windows编程之多线程事件对象(Event Object)用法详解

目录

一、前言

二、基础用法

三、API详解

1.创建事件对象

2控制事件状态

3.等待事件对象:

四、实战案例

1.案例描述 

2.代码设计

 3.总设计代码

4.运行结果


一、前言

        事件对象(Event Object)是我们在大型项目中,进行多线程同步处理的时候经常用到的一种内核对象,下面我就根据它的基础本身的特点和相关的API函数,与实战案例相结合,讲述它的基础理论和用法。

二、基础用法

        在Windows编程中,事件对象(Event Objects)是一种内核对象,主要用于线程之间的同步。当多个进程需要访问共享资源时,可以通过CreateEvent创建的事件对象来控制访问顺序,避免资源冲突和数据不一致的问题。

        事件对象中经常结合进行使用的有以下四种api函数,我们掌握了这四种API函数的基本用法,可以说就掌握了事件对象(Event Object)。以下api函数分别为 CreateEvent , SetEvent,

ResetEvent  WaitForSingleObject。后面我会依次讲解各个api函数的原型以及作用。

三、API详解

1.创建事件对象

           我们可以使用 CreateEven 函数来创建一个事件对象,它是一个Windows API函数,这个函数允许你指定事件对象的安全属性、是手动重置还是自动重置、以及它的初始状态(信号态或非信号态)。下面是它的原型:

HANDLE WINAPI CreateEventW(_In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,   //安全属性_In_ BOOL bManualReset,  // 复位方式:true 必须用 resetevent手动复原 false 自动还原为无信号状态_In_ BOOL bInitialState,  //初始状态 : true 初始状态为有信号状态: false 无信号状态_In_opt_ LPCWSTR lpName    //对象名称: null 无名的事件对象);

        可以根据原型解释,它的返回值类型为 句柄(空指针) ,函数约束类型为 WINAPI (_stdcall)

        第一个参数为  lpEventAttributes ,也就是安全属性,它是作为windows内核对象必须要有的参数类型。

        第二个参数是指复位方式,如果为TRUE,则事件对象需要显式调用ResetEvent函数来重置为无信号状态;如果为FALSE,则事件对象在单个等待线程被释放后自动重置为无信号状态。

        第三个参数为信号状态也就是指定事件对象的初始状态,如果为TRUE,则事件对象被创建时处于有信号状态;如果为FALSE,则处于无信号状态。

        第四个参数为指定事件对象的名称,通常为NULL,为无名的事件对象。

2控制事件状态

        事件对象有两种状态——发信号和不发信号。

       SetEvent:将事件对象的状态置为发信号状态,允许等待该事件的线程继续执行。

       ResetEvent:将事件对象的状态置为不发信号状态。

WINBASEAPI BOOL WINAPI SetEvent(_In_ HANDLE hEvent);WINBASEAPI BOOL WINAPI ResetEvent(_In_ HANDLE hEvent);

        原型为上述代码,参数都是为 HANDLE (句柄),也就是 CreateEven 函数的返回值,

3.等待事件对象

      使用 WaitForSingleObject 或 WaitForMultipleObjects 函数等待一个或多个事件对象变为信号态, 线程才会继续向下执行。

        函数原型如下,参数都大致相同。

WINBASEAPI DWORD WINAPI WaitForSingleObject(_In_ HANDLE hHandle,_In_ DWORD dwMilliseconds);

四、实战案例

        上面我们已经讲述了事件对象的作用以及一些常用的api方法和属性,下面我将会通过一个实际有代表性的案例来继续讲解事件对象,来加深它的用法和印象。

1.案例描述 

        下面游乐园有两个售票口 A 和 售票口 B,游乐园限制最多100人进,假设这两个售票口所卖的是不同种类的票,一共有100张。那么该如何设计程序,保证售票口 A 和 售票口 B 同时所卖的票不是同一张票。

2.代码设计

        上述案例我们可以用编程的角度去分析问题和解决问题。

        售票口 A 和 售票口 B 可以分别看作两个线程,线程 A和线程 B。100张票可以当作全局变量,作为线程A,B需要访问的公共资源。代码设计为:

#include <stdio.h>
#include <windows.h>
#include <process.h>// 共享资源 (100张票)
int iTickets = 100;// 事件对象
HANDLE g_hEvent;int main()
{// 线程A 和 线程BHANDLE hThreadA, hThreadB;hThreadA = CreateThread(NULL, 0, SellTicketA, NULL, 0, 0);hThreadB = CreateThread(NULL, 0, SellTicketB, NULL, 0, 0);CloseHandle(hThreadA); CloseHandle(hThreadB);system("pause");return 0;
}

        那么就只需要保证线程A 和 线程 B在同一时间只能对共享资源的单一访问,这里我们就可以用到事件对象(Event Objects)。

    //手动重置 FALSE:设置无信号状态,未触发状态g_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);SetEvent(g_hEvent);Sleep(4000);CloseHandle(g_hEvent);

        具体做法为 进程A 可以通过 SetEvent函数 将事件对象的状态设置为有信号状态,进程B 则可以通 WaitForSingleObject 等函数等待该事件对象变为有信号状态,从而实现进程间的信号传递和协调,代码为:

    while (1){WaitForSingleObject(g_hEvent, INFINITE);if (iTickets > 0){Sleep(1);iTickets--;printf("A remain %d\n",iTickets);}else{break;}SetEvent(g_hEvent);}return 0;
 3.总设计代码

        以下是设计的总代码:

#include <stdio.h>
#include <windows.h>
#include <process.h>// 共享资源 (100张票)
int iTickets = 100;// 事件对象
HANDLE g_hEvent;DWORD WINAPI SellTicketA(void* arg)
{while (1){WaitForSingleObject(g_hEvent, INFINITE);if (iTickets > 0){Sleep(1);iTickets--;printf("A remain %d\n",iTickets);}else{break;}SetEvent(g_hEvent);}return 0;
}
DWORD WINAPI SellTicketB(void* arg)
{while (1){WaitForSingleObject(g_hEvent, INFINITE);if (iTickets > 0){Sleep(1);iTickets--;printf("B remain %d\n", iTickets);}else{break;}SetEvent(g_hEvent);}return 0;
}int main()
{// 线程A 和 线程BHANDLE hThreadA, hThreadB;hThreadA = CreateThread(NULL, 0, SellTicketA, NULL, 0, 0);hThreadB = CreateThread(NULL, 0, SellTicketB, NULL, 0, 0);CloseHandle(hThreadA); CloseHandle(hThreadB);//手动重置 FALSE:设置无信号状态,未触发状态g_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);SetEvent(g_hEvent);Sleep(4000);CloseHandle(g_hEvent);system("pause");return 0;
}
4.运行结果

        代码运行的总结果如下。

 

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

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

相关文章

竞赛选题 医学大数据分析 - 心血管疾病分析

文章目录 1 前言1 课题背景2 数据处理3 数据可视化4 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的心血管疾病分析 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9…

AI绘画Stable Diffusion 解锁精美壁纸创作:利用SD与LLM定制你的专属壁纸,AI副业变现指南!

大家好&#xff0c;我是画画的小强 今天给大家分享一下用AI绘画Stable Diffusion 制作精美手机壁纸&#xff0c;这也可能是当前最快AIGC变现的一种途径。虽然本文的主题为手机壁纸&#xff0c;当调整不同的比例的分辨率宽高比例&#xff0c;就可以直接复用到手机、电脑和平板、…

机器学习原理之 -- 支持向量机分类:由来及原理详解

支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是统计学习理论的一个重要成果&#xff0c;广泛应用于分类和回归问题。SVM以其高效的分类性能和良好的泛化能力在机器学习领域中占据重要地位。本文将详细介绍支持向量机的由来、基本原理、构建过程及其优缺点。…

LVS负载均衡群集部署之——DR模式的介绍及搭建步骤

一、LVS-DR集群介绍1.1 LVS-DR 工作原理1.2 数据包流向分析1.3 LVS-DR 模式的特点1.4 LVS-DR中的ARP问题1.4.1 问题一1.4.2 问题二二、构建LVS-DR集群2.1 构建LVS-DR集群的步骤&#xff08;理论&#xff09;1.配置负载调度器&#xff08;192.168.80.30&#xff09;&#xff08;…

5分钟教你用AI把老照片动起来,别再去花49块9的冤枉钱了

文章目录 需要的工具 最近&#xff0c;AI视频在各大平台上&#xff0c;又火了。 只是火的形式&#xff0c;变成了将老照片动起来&#xff0c;打情感牌&#xff0c;或者做很多经典电视剧的再整活。 直接把可灵的生成时间&#xff0c;从以前的4分钟&#xff0c;生生的干成了20分钟…

鸿蒙应用笔记

安装就跳过了&#xff0c;一直点点就可以了 配置跳过&#xff0c;就自动下了点东西。 鸿蒙那个下载要12g个内存&#xff0c;大的有点吓人。 里面跟idea没区别 模拟器或者真机运行 真机要鸿蒙4.0&#xff0c;就可以实机调试 直接在手机里面跑&#xff0c;这个牛逼&#xf…

国标GB/T 28181详解:国标GBT28181-2022 SIP服务器发起广播的命令流程

目录 一、定义 二、作用 1、实现信息的集中管理和分发 &#xff08;1&#xff09;信息集中 &#xff08;2&#xff09;信息分发 2、提高信息传输的可靠性和效率 &#xff08;1&#xff09;可靠性 &#xff08;2&#xff09;提高效率 3、支持多种设备和系统的互通 &am…

mongdb学习与使用

1. 基础概念 MongoDB简介&#xff1a; MongoDB是一个基于文档的NoSQL数据库&#xff0c;具有高性能、高可用性和易扩展性。数据存储在类似JSON的BSON格式中。 基本术语&#xff1a; Database&#xff08;数据库&#xff09;&#xff1a; 集合的容器。Collection&#xff08;集合…

国产强大免费WAF, 社区版雷池动态防护介绍

雷池WAF&#xff0c;基于智能语义分析的下一代 Web 应用防火墙 使用情况 我司于2023年4月23日对雷池进行测试&#xff0c;测试一个月后&#xff0c;于2023年5月24日对雷池进行正式切换&#xff0c;此时版本为1.5.1。 里程碑纪念 后续一直跟随雷池进行版本升级&#xff0c;当前…

QT_GUI

1、QT安装 一个跨平台的应用程序和用户界面框架&#xff0c;用于开发图形用户界面&#xff08;GUI&#xff09;应用程序以及命令行工具。QT有商业版额免费开源版&#xff0c;一般使用免费开源版即可&#xff0c;下面安装的是QT5&#xff0c;因为出来较早&#xff0c;使用较多&…

Python特征工程 — 1.4 特征归一化方法详解

目录 1 Min-Max归一化 方法1&#xff1a;自定义的Min-Max归一化封装函数 方法2&#xff1a; scikit-learn库中的MinMaxScaler 2 Z-score归一化 方法1&#xff1a;自定义的Z-score归一化封装函数 方法2&#xff1a; scikit-learn库中的StandardScaler 3 最大值归一化 4 L…

考研生活day1--王道课后习题2.2.1、2.2.2、2.2.3

2.2.1 题目描述&#xff1a; 解题思路&#xff1a; 这是最基础的操作&#xff0c;思路大家应该都有&#xff0c;缺少的应该是如何下笔&#xff0c;很多同学都是有思路但是不知道如何下笔&#xff0c;这时候看思路的意义不大&#xff0c;可以直接看答案怎么写&#xff0c;最好…

Java项目:基于SSM框架实现的游戏攻略网站系统分前后台【ssm+B/S架构+源码+数据库+毕业论文+任务书】

一、项目简介 本项目是一套基于SSM框架实现的游戏攻略网站系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能…

redhat7.x 升级openssh至openssh-9.8p1

1.环境准备&#xff1a; OS系统&#xff1a;redhat 7.4 2.备份配置文件&#xff1a; cp -rf /etc/ssh /etc/ssh.bak cp -rf /usr/bin/openssl /usr/bin/openssl.bak cp -rf /etc/pam.d /etc/pam.d.bak cp -rf /usr/lib/systemd/system /usr/lib/systemd/system.bak 3.安装…

UB9A0全系统全频高精度板卡性能指标

UB9A0 板卡是基于和芯星通自主研发的新一代射频基带及高精度算法一体化 GNSS SoC 芯片—Nebulas Ⅳ开发的全系统全频点高精 OEM 板卡 &#xff0c;支持 BDS&#xff0c;GPS&#xff0c; GLONASS&#xff0c;Galileo&#xff0c;QZSS&#xff0c;NavIC&#xff0c;SBAS&#xff…

MySQL环境搭配

下载版本37滴 下载第二个 之后进行安装 进入安装界面 next 选择默认的 进行下一步 安装成功后&#xff0c;进行一系列配置&#xff0c;成功界面如下&#xff1a; 配置 MySQL8.0 环境变量 如果不配置 MySQL 环境变量&#xff0c;就不能在命令行直接输入 MySQL 登录命令。 步…

强烈推荐!12 组超惊艳的 Midjourney 风格提示词!

前言 Midjourney 的 --sref random 随机风格功能推出之后&#xff0c;出现了很多对不同代码生成效果的探索。今天就为大家推荐 12 组我觉得非常惊艳的风格代码&#xff0c;将它们添加在提示词中&#xff0c;不需要写复杂的关键词就能得到高质量的指定风格&#xff0c;并且效果…

CUDA编译配置中来自 CUDA 12.1.targets 的MSB3721错误和核函数调用语法错误‘<’解决及可用的代码示例框架

今天开始整cuda编程处理图像&#xff0c;好久没玩cuda&#xff0c;又从小白开始。情况不妙&#xff0c;第一个工程坑不少&#xff0c;记录一下如下2个重要的错误&#xff1a; &#xff08;1&#xff09;来自 CUDA 12.1.targets 的MSB3721错误 错误 命令““C:\Program Files\N…

Scrapy框架的基本使用教程

1、创建scrapy项目 首先在自己的跟目录文件下执行命令&#xff1a; PS D:\BCprogram\python_pro\bigdata> scrapy startproject theridion_grallatorscrapy startproject 项目名 具体执行操作如下&#xff1a;1、创建项目目录&#xff1a;Scrapy会在当前工作目录下创建一…

Git 操作总结

1. 安装、Git 环境配置 1.1 安装 Git 官方版本可以在 Git 官方网站下载&#xff1a;打开 https://git-scm.com/download/win&#xff0c;选择相应版本即可。 Git 安装完成后&#xff0c;可以在开始菜单中看到 Git 的三个启动图标&#xff08;Git Bash、Git CMD、Git GUI&…