线程中CreateEvent、SetEvent、WaitForSingleObject的用法

article/2025/10/15 9:29:57

原文地址:https://www.cnblogs.com/MrYuan/p/5238749.html

首先介绍CreateEvent是创建windows事件的意思,作用主要用在判断线程退出,线程锁定方面.

CreateEvent

函功能描述:创建或打开一个命名的或无名的事件对象.

EVENT有两种状态:发信号,不发信号。 

SetEvent/ResetEvent分别将EVENT置为这两种状态分别是发信号与不发信号。 

WaitForSingleObject()等待,直到参数所指定的OBJECT成为发信号状态时才返回,OBJECT可以是EVENT,也可以是其它内核对象。

当你创建一个线程时,其实那个线程是一个循环,不像上面 那样只运行一次的。这样就带来了一个问题,在那个死循环里要找到合适的条件退出那个死循环,那么是怎么样实现它的呢?在Windows里往往是采用事件的 方式,当然还可以采用其它的方式。在这里先介绍

采用事件的方式来通知从线程运行函数退出来,它的实现原理是这样,在那个死循环里不断地使用 WaitForSingleObject函数来检查事件是否满足,如果满足就退出线程,不满足就继续运行。当在线程里运行阻塞的函数时,就需要在退出线程 时,先要把阻塞状态变成

非阻塞状态,比如使用一个线程去接收网络数据,同时使用阻塞的SOCKET时,那么要先关闭SOCKET,再发送事件信号,才可以 退出线程的。

当然我感觉重要应用方面还是用来锁定,实现所谓的pv功能。

下面介绍函数功能,参数等

1.CreateEvent

函数功能描述:创建或打开一个命名的或无名的事件对象

函数原型:

HANDLE CreateEvent(

  LPSECURITY_ATTRIBUTES lpEventAttributes,   // 安全属性

  BOOL bManualReset,   // 复位方式

  BOOL bInitialState,   // 初始状态

  LPCTSTR lpName   // 对象名称

);

参数:

lpEventAttributes:

      [输入]一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承。如果lpEventAttributes是NULL,此句柄不能被继承。

      Windows NT/2000:lpEventAttributes的结构中的成员为新的事件指定了一个安全符。如果lpEventAttributes是NULL,事件将获得一个默认的安全符。

bManualReset:

      [输入]指定将事件对象创建成手动复原还是自动复原。如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。如果设置为FALSE,当事件被一个等待线程释放以后,系统将会自动将事件状态复原为无信号状态。

bInitialState:

      [输入]指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。

lpName:

      [输入]指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。

      如果lpName指定的名字,与一个存在的命名的事件对象的名称相同,函数将请求EVENT_ALL_ACCESS来访问存在的对象。这时候,由于 bManualReset和bInitialState参数已经在创建事件的进程中设置,这两个参数将被忽略。如果lpEventAttributes是 参数不是NULL,它将确定此句柄是否可以被继承,但是其安全描述符成员将被忽略。

      如果lpName为NULL,将创建一个无名的事件对象。

      如果lpName的和一个存在的信号、互斥、等待计时器、作业或者是文件映射对象名称相同,函数将会失败,在GetLastError函数中将返回ERROR_INVALID_HANDLE。造成这种现象的原因是这些对象共享同一个命名空间。

      终端服务(Terminal Services):名称中可以加入"Global\"或是"Local\"的前缀,这样可以明确的将对象创建在全局的或事务的命名空间。名称的其它部分 除了反斜杠(\),可以使用任意字符。详细内容可参考Kernel Object Name Spaces。

      Windows 2000:在Windows 2000系统中,没有终端服务运行,"Global\"和"Local\"前缀将被忽略。名称的其它部分除了反斜杠(\),可以使用任意字符。

      Windows NT 4.0以及早期版本, Windows 95/98:名称中除了反斜杠(\),可以使用任意字符。

返回值:

       如果函数调用成功,函数返回事件对象的句柄。如果对于命名的对象,在函数调用前已经被创建,函数将返回存在的事件对象的句柄,而且在GetLastError函数中返回ERROR_ALREADY_EXISTS。

      如果函数失败,函数返回值为NULL,如果需要获得详细的错误信息,需要调用GetLastError。

备注:

      调用CreateEvent函数返回的句柄,该句柄具有EVENT_ALL_ACCESS权限去访问新的事件对象,同时它可以在任何有此事件对象句柄的函数中使用。

      在调用的过程中,所有线程都可以在一个等待函数中指定事件对象句柄。当指定的对象的状态被置为有信号状态时,单对象等待函数将返回。

      对于多对象等待函数,可以指定为任意或所有指定的对象被置为有信号状态。当等待函数返回时,等待线程将被释放去继续运行。

      初始状态在bInitialState参数中进行设置。使用SetEvent函数将事件对象的状态置为有信号状态。使用ResetEvent函数将事件对象的状态置为无信号状态。

      当一个手动复原的事件对象的状态被置为有信号状态时,该对象状态将一直保持有信号状态,直至明确调用ResetEvent函数将其置为无符号状态。

      当事件的对象被置为有信号状态时,任意数量的等待中线程,以及随后开始等待的线程均会被释放。

      当一个自动复原的事件对象的状态被置为有信号状态时,该对象状态将一直保持有信号状态,直至一个等待线程被释放;系统将自动将此函数置为无符号状态。如果没有等待线程正在等待,事件对象的状态将保持有信号状态。

      多个进程可持有同一个事件对象的多个句柄,可以通过使用此对象来实现进程间的同步。下面的对象共享机制是可行的:

      ·在CreateEvent函数中,lpEventAttributes参数指定句柄可被继承时,通过CreateProcess函数创建的子进程继承的事件对象句柄。

      ·一个进程可以在DuplicateHandle函数中指定事件对象句柄,从而获得一个复制的句柄,此句柄可以被其它进程使用。

      ·一个进程可以在OpenEvent或CreateEvent函数中指定一个名字,从而获得一个有名的事件对象句柄。

      使用CloseHandle函数关闭句柄。当进程停止时,系统将自动关闭句柄。当最后一个句柄被关闭后,事件对象将被销毁。

使用环境:

      Windows NT/2000:需要3.1或更高版本

      Windows 95/98:需要Windows 95或更高版本

      头文件:定义在Winbase.h;需要包含 Windows.h。

      导入库:user32.lib

      Unicode:在Windows NT/2000中,以 Unicode 和 ANSI 执行

    一个Event被创建以后,可以用OpenEvent()API来获得它的Handle,用CloseHandle()   

    来关闭它,用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent()   

    来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待   

    其变为有信号.   

 

    PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event   

    对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的.   

    对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于   

    人工复位的Event对象,它释放所有等待的thread.  


2.    WaitForSingleObject的用法                                       

WaitForSingleObject的用法

DWORD WINAPI WaitForSingleObject(

__in HANDLE hHandle,      // 句柄

__in DWORD dwMilliseconds   // 时间间隔

);

 

hHandle[in]对象句柄。可以指定一系列的对象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。

dwMilliseconds[in]定时时间间隔,单位为milliseconds(毫秒).如果指定一个非零值,函数处于等待状态直到hHandle标记的对象被触发,或者时间到了。如果dwMilliseconds为0,对象没有被触发信号,函数不会进入一个等待状态,它总是立即返回。如果dwMilliseconds为INFINITE,对象被触发信号后,函数才会返回。

 

执行成功,返回值指示出引发函数返回的事件。它可能为以下值:

WAIT_ABANDONED0x00000080L

The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread and the mutex state is set to nonsignaled.

If the mutex was protecting persistent state information, you should check it for consistency.

WAIT_OBJECT_00x00000000L

The state of the specified object is signaled.

WAIT_TIMEOUT0x00000102L

The time-out interval elapsed, and the object's state is nonsignaled.

WAIT_FAILED(DWORD)0xFFFFFFFF

The function has failed. To get extended error information, callGetLastError.

 

WaitForSingleObject函数用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。

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

WAIT_OBJECT_0 0x00000000 :指定的对象出有有信号状态

WAIT_TIMEOUT 0x00000102:等待超时

WAIT_FAILED 0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码

在这里举个例子:

先创建一个全局Event对象g_event:

CEvent g_event;

在程序中可以通过调用CEvent::SetEvent设置事件为有信号状态。

下面是一个线程函数MyThreadProc()

复制代码

UINT CFlushDlg::MyThreadProc( LPVOID pParam )
{WaitForSingleObject(g_event,INFINITE);For(;;){………….}return 0;
}    

复制代码

在这个线程函数中只有设置g_event为有信号状态时才执行下面的for循环,因为g_event是全局变量,所以我们可以在别的线程中通过g_event. SetEvent控制这个线程。

还有一种用法就是我们可以通过WaitForSingleObject函数来间隔的执行一个线程函数的函数体

复制代码

UINT CFlushDlg::MyThreadProc( LPVOID pParam )
{while(WaitForSingleObject(g_event,MT_INTERVAL)!=WAIT_OBJECT_0){//……}return 0;
}

复制代码

在这个线程函数中可以通过设置MT_INTERVAL来控制这个线程的函数体多久执行一次,当事件为无信号状态时函数体隔MT_INTERVAL执行一次,当设置事件为有信号状态时,线程就执行完毕了。


http://chatgpt.dhexx.cn/article/cVrwjAG5.shtml

相关文章

CreateEvent SetEvent WaitForSingleObjec

在自动重置事件对象中,当WaitSingleObject/WaitForMultipleObjects接收到SetEvent发送过来的信号后则返回WAIT_OBJECT_0,此时操作系统(待定)自动重置等待的事件对象(即自动将其设置为无信号状态。无论何时通过SetEvent…

线程中CreateEvent和SetEvent及WaitForSingleObject的用法

首先介绍CreateEvent是创建windows事件的意思,作用主要用在判断线程退出,线程锁定方面. CreateEvent 函功能描述:创建或打开一个命名的或无名的事件对象. EVENT有两种状态:发信号,不发信号。 SetEvent/ResetEvent…

wireshark找不到接口?你的NPF没启动

使用wireshark时会遇到找不到接口的问题,这是因为电脑的NPF没有启动。以管理员身份运行cmd,输入net start npf即可。不过,电脑重启后,它又关闭了。

wireshark抓包报错The capture session could not be initiated on interface '\Device\NPF_Loopback'

wireshark抓包报错 The capture session could not be initiated on interface ‘\Device\NPF_Loopback’ (Error opening adapter: The system cannot find the path specified. (3)). 解决方法 以管理员身份运行cmd,输入net start npcap 重新打开wireshark即可…

The NPF or NPCAP service is not installed, please install Winpcap or Npcap aand reboot的解决方法

安装好GNS启动后,我遇到了GNS3没有加载的错误,并且发出错误声明“未安装NPF或NPCAP服务,请安装Winpcap或Npcap并重启。” 确认已经安装了winpcap,怎么还会报错呢??后来发现是没有勾选自启动winpcap软件导致…

wireshark提示未启动npf服务The NPF driver isn’t running You may have trouble capturing or listing interfaces

提示未启动npf服务的解决办法 检查你的电脑有没有安装WinPcap,如果没有安装就安装一下以管理员身份运行cmd.exe,执行命令:sc config npf start auto,重启wireshark如果还提示未启动npf服务就执行这个命令:net start n…

解决启动Wireshark时遇到的“The NPF driver isn't running...”

最近在使用wireshark抓包软件的时候遇到了这个问题,在启动wireshark的时候,会弹出一个对话框: 上网搜索了一下,结合自己的想法,得到如下两个解决方法: 一、图形界面操作 1、右击计算机,“管理”…

wireshark/The NPF driver isn’t running./Unable to load WinPcap (wpcap.dll)

很久没使用wireshark后重新打开就出现警告: The NPF driver isn’t running. You may have trouble capturing or listing interfaces. 点击菜单栏caption,准备启动的时候,又显示警告框,直接不给操作: Unable to load …

使用Wireshark抓包软件提示The NPF driver isn’t running解决办法

Wireshark一个强大的数据抓包分析工具,在Win7 64位系统上第一次使用时,可能会出现意外的情况。 The NPF driver isn’t running. 这个情况可能是因为没有安装Winpcap驱动或者安装Winpcap时没有选中开机自动启动winpcap选项。 解决方法: 1. 没…

【西门子】S7-PLCSIM Advance_V2/V3, Error Code: -30,LicenseNotFound /NetGroup Packet Filter Driver (NPF)

最近公司需要测试视觉程序与西门子S7-1500通讯,下载了下西门子的编程程序进行通讯测试,本来想着安装个程序很简单的事,谁知道在使用S7-PLCSIM Advance_V3仿真通讯时遇到各种问题,鉴于自己踩坑太多,特此分享自己的完美解…

wireshark找不到捕获接口问题和net start npf 服务器名无效、拒绝访问的解决办法

win10系统 解决方法: 1、去官网下载用于网络封包抓取的工具 winpcap 链接:https://www.winpcap.org/install/bin/WinPcap_4_1_3.exe 2、用管理员身份运行命令提示符 3、输入net start npf 启动服务 可以看到有捕获接口了

Wireshark学习篇(1)---NPF driver is not running error

在互联网这个行业里,怎能不熟悉几款抓包工具呢。将Wireshark作为首选学习工具,此工具功能比较强大,是基于网卡级别进行的抓包。在电脑上安装了 Wireshark后,首次登录的时候,会有"NPF driver is not running"…

[安装wireshark时,报“Error opening file for writing npf.sys”]

问题来源: 最近拷贝了别人一个win10的虚拟机,用wireshark抓帧时,一直找不到wifi的网卡,导致抓不了帧。 查找问题: 在win10下输入命令: C:\Program Files\Wireshark>tshark -DThe NPF driver isnt run…

解决打开S7-PLCSIM Advanced V3.0报错NetGroup Packet Filter Driver (NPF)

在安装S7-PLCSIM Advanced V3.打开仿真的时候网卡报错。以管理员模式打开cmd,输入net start npf开启npf的时候显示服务名无效,原因是没有安装winpcap,在安装winpcap后再以管理员模式运行cmd,输入net start npf后成功打开npf。本文…

win7环境下 net start npf服务名无效的解决方法。

一、这个问题的起因是wireshark找不到本地接口引起的,在网上找到的解决方法是:把 新版的winpcap删除再重装个老版的。(再次证明软件还是用老的好,新的有BUG)。 操作方法如下:找到对应的文件,并把扩展名修改即可。 C:\…

net start npf启用失败问题解决 net start npf 发生系统错误5、net start npf 服务名无效

问题1:net start npf 服务名无效 Wireshark找不到网卡 输入net start npf 服务名无效 解决办法1:下载winpcap 地址:https://www.winpcap.org/install/bin/WinPcap_4_1_3.exe 安装完winpcap,在cmd(要以管理员模式运行…

[转]NPF驱动核心指南(含与NDIS区别)

这是WinPcap的NPF驱动核心指南原文的翻译,英语水平有限,翻译得可能不是很准确。 这个章节说明网络组包过滤(NPF)组件-WinPcap的核心部分。一般用户可能只对WinPcap的使用感兴趣,但不一定想了解它的组件结构…

贝叶斯文本分类

朴素贝叶斯分类 贝叶斯分类 贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类而朴素朴素贝叶斯分类是贝叶斯分类中最简单,也是常见的一种分类方法分类问题综述 对于分类问题,其实谁都不会陌生&am…

贝叶斯分类numpy实现

概述 贝叶斯属于生成模型的一种,其实现很简单,就是应用贝叶斯公式。这是一种指定先验分布,求后验的方法。 概率论课本里著名的贝叶斯公式如下 p(ci)是i类在数据集的占比,(数一下就可,易) p(x|…

python编程实现贝叶斯分类

贝叶斯的思想比较简单,网上阐述也很详细,这里就不赘述了。 这里只是简单的说一下编程的思路 首先明确我们要实验的内容,实现贝叶斯分类,那么要想编程实现,你必须对贝叶斯分类有足够的了解。而贝叶斯分类的过程并不难&a…