c++中CreateEvent函数

函数原型:

  1. HANDLE CreateEvent(
  2. LPSECURITY_ATTRIBUTES lpEventAttributes,
  3. BOOL bManualReset,
  4. BOOL bInitialState,
  5. LPCTSTR lpName
  6. );

lpEventAttributes:指向SECURITY_ATTRIBUTES结构体,此结构体决定函数的返回句柄是否可以让子进程继承。如果这个参数为NULL,这个句柄是不能继承的。一般情况下,这个参数设置为NULL。

bManualReset:指定将创建的EVENT是自动复位还是手动复位。如果为TRUE,需要用ResetEvent(HANDLE)函数手动复位状态为无信号,即一旦改EVENT被设置成有信号,则它会一直等到ResetEvent调用时才为无信号状态。如果为FALSE,当一个有信号的等待线程被释放后,系统会自动复位状态为无信号状态。

bInitialState:指定事件对象的初始状态。如果为TRUE,初始状态为有信号,否则为无信号。

lpName: 事件对象的名称,以字符串表示。名称的长度受MAX_PATH的限制,名称是大小写敏感的。如果lpName匹配一个存在的命名的事件对象,函数将请求EVENT_ALL_ACCESS来访问存在的对象。在这种情况下,bManualReset和bInitialState 被忽略,因为这两个参数已经被存在的事件设置。如果lpEventAttributes参数不为NULL,这个参数可以决定是否句柄被继承,但是它的安全描述(security-descriptor)成员被忽略。如果lpName 为NULL,创建一个没有名称的事件。如果lpName 匹配一个存在的semaphore, mutex, waitable timer, job或者file-mapping对象的名称,函数调用失败,GetLastError函数返回ERROR_INVALID_HANDLE。由于这些对象共享相同的命名空间,才导致这种情况的发生。

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

调用过程中的任何线程,都可以在一个等待函数中指定事件对象句柄。当指定的对象的状态为有信号时,单对象等待函数(例如WaitForSingleObject)返回。对于多对象等待函数(例如WaitForMultipleObjects),可以指定为任意或所有指定的对象被置为有信号状态。当等待函数返回时,等待线程将被释放去继续它的执行。 事件对象的初始状态由bInitialState参数指定,用SetEvent函数可以设置对象为有信号状态,用ResetEvent函数可以设置对象为无信号状态。 当一个手动复原的事件对象的状态被置为有信号状态时,该对象将一直保持有信号状态,直至明确调用ResetEvent函数将其置为无符号状态。当事件对象被设置为有信号状态时,任何数量的等待线程或者随后等待的线程都会被释放。

当一个自动复原事件对象的状态被设置为有信号状态时,该对象一直保持有信号状态,直至一个单等待线程被释放;系统然后会自动重置对象到无信号状态。

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

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

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

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

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

二、C++CreateEvent函数在多线程中使用及实例

下面主要演示一下采用CreateEvent实现多线程。

例子很简单,主要测试CreateEvent中 bManualReset:和 _bInitialState_参数的取值在线程调用中信号状态的情况。

测试1:

bManualReset:TRUE
bInitialState:TRUE

CreateEvent(NULL, TRUE, TRUE, NULL); //使用手动重置为无信号状态,初始化时有信号状态

example.cpp

  1. include “iostream”

  2. include “windows.h”

  3. using namespace std;
  4. DWORD WINAPI ThreadProc1(LPVOID lpParam);
  5. DWORD WINAPI ThreadProc2(LPVOID lpParam);
  6. HANDLE hEvent = NULL;
  7. HANDLE hThread1 = NULL;
  8. HANDLE hThread2 = NULL;
  9. int main(int argc, char *args[])
  10. {
  11. hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  12. hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, NULL, 0,NULL);
  13. Sleep(200);
  14. hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc2, NULL, 0,NULL);
  15. Sleep(200);
  16. if ( NULL == hThread1)
  17. {
  18. cout <<“create thread fail!”;
  19. }
  20. return 0;
  21. }
  22. DWORD WINAPI ThreadProc1(LPVOID lpParam)
  23. {
  24. cout <<“in thread1@!”<
  25. DWORD dReturn = WaitForSingleObject(hEvent,INFINITE);
  26. if ( WAIT_OBJECT_0 == dReturn)
  27. {
  28. cout <<” thread1 signaled ! “<
  29. }
  30. cout <<“in thread1 –signal”<
  31. return 0;
  32. }
  33. DWORD WINAPI ThreadProc2(LPVOID lpParam)
  34. {
  35. cout <<“in thread2@!”<
  36. DWORD dReturn = WaitForSingleObject(hEvent,INFINITE);
  37. if ( WAIT_OBJECT_0 == dReturn)
  38. {
  39. cout <<“thread2 signaled ! “<
  40. }
  41. cout <<“in thread2–signal”<
  42. return 0;
  43. }

执行结果:

c++中CreateEvent函数

从结果中看,执行完线程1又执行了线程2.

由于hEvent = CreateEvent(NULL, TRUE, TRUE, NULL),使用手动重置为无信号状态,初始化时有信号状态

所以hEvent一直处于有信号状态,无论是线程1释放后,hEvent仍处于有信号状态,所以线程2正常执行了。

测试2:

bManualReset:FALSE
bInitialState:TRUE

  1. hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);

example2.cpp

  1. include “iostream”

  2. include “windows.h”

  3. using namespace std;
  4. DWORD WINAPI ThreadProc1(LPVOID lpParam);
  5. DWORD WINAPI ThreadProc2(LPVOID lpParam);
  6. HANDLE hEvent = NULL;
  7. HANDLE hThread1 = NULL;
  8. HANDLE hThread2 = NULL;
  9. int main(int argc, char *args[])
  10. {
  11. hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
  12. hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, NULL, 0,NULL);
  13. Sleep(200);
  14. hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc2, NULL, 0,NULL);
  15. Sleep(200);
  16. if ( NULL == hThread1)
  17. {
  18. cout <<“create thread fail!”;
  19. }
  20. return 0;
  21. }
  22. DWORD WINAPI ThreadProc1(LPVOID lpParam)
  23. {
  24. cout <<“in thread1@!”<
  25. DWORD dReturn = WaitForSingleObject(hEvent,INFINITE);
  26. if ( WAIT_OBJECT_0 == dReturn)
  27. {
  28. cout <<” thread1 signaled ! “<
  29. }
  30. cout <<“in thread1 –signal”<
  31. return 0;
  32. }
  33. DWORD WINAPI ThreadProc2(LPVOID lpParam)
  34. {
  35. cout <<“in thread2@!”<
  36. DWORD dReturn = WaitForSingleObject(hEvent,INFINITE);
  37. if ( WAIT_OBJECT_0 == dReturn)
  38. {
  39. cout <<“thread2 signaled ! “<
  40. }
  41. cout <<“in thread2–signal”<
  42. return 0;
  43. }

执行结果:

c++中CreateEvent函数

从执行结果中分析,执行了线程1,线程2一直在等待,直到主线程结束。

由于hEvent = CreateEvent(NULL, FALSE, TRUE, NULL),当一个等待线程被释放时,自动重置为无信号状态,初始是有信号状态

初始执行线程1的时候,hEvent是有信号的,所以线程1正常执行;又由于 bManualReset=FALSE,所以执行完线程1后,hEven

[cpp]
view plain copy

  1. WaitForSingleObject(hEvent,INFINITE);

函数一直在等待hEvent变为有信号状态,但是当主线程执行完,还没等待到,线程2程序一直没有走下去。

测试3:

bManualReset:TRUE
bInitialState:FALSE

hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);//使用手动重置为无信号状态,初始化时为无信号状态

example3.cpp

[cpp]
view plain copy

  1. include “iostream”

  2. include “windows.h”

  3. using namespace std;
  4. DWORD WINAPI ThreadProc1(LPVOID lpParam);
  5. DWORD WINAPI ThreadProc2(LPVOID lpParam);
  6. HANDLE hEvent = NULL;
  7. HANDLE hThread1 = NULL;
  8. HANDLE hThread2 = NULL;
  9. int main(int argc, char *args[])
  10. {
  11. hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  12. hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, NULL, 0,NULL);
  13. Sleep(200);
  14. hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc2, NULL, 0,NULL);
  15. Sleep(200);
  16. if ( NULL == hThread1)
  17. {
  18. cout <<“create thread fail!”;
  19. }
  20. return 0;
  21. }
  22. DWORD WINAPI ThreadProc1(LPVOID lpParam)
  23. {
  24. cout <<“in thread1@!”<
  25. DWORD dReturn = WaitForSingleObject(hEvent,INFINITE);
  26. if ( WAIT_OBJECT_0 == dReturn)
  27. {
  28. cout <<” thread1 signaled ! “<
  29. }
  30. cout <<“in thread1 –signal”<
  31. return 0;
  32. }
  33. DWORD WINAPI ThreadProc2(LPVOID lpParam)
  34. {
  35. cout <<“in thread2@!”<
  36. DWORD dReturn = WaitForSingleObject(hEvent,INFINITE);
  37. if ( WAIT_OBJECT_0 == dReturn)
  38. {
  39. cout <<“thread2 signaled ! “<
  40. }
  41. cout <<“in thread2–signal”<
  42. return 0;
  43. }

执行结果,可想而知,只能输出:
in thread1@!

in thread2@!

因为初始为无信号状态,所以hEvent一直处于无信号状态,因此这两个线程一直在等待,直到主线程结束。

修改:放开例子中的注释部分:

if (SetEvent(hEvent))//设置信号为有信号状态
{
cout << “setEvent 成功” <

执行结果:

c++中CreateEvent函数

可见,线程1和线程2都执行了。

因为调用SetEvent,事件变为有信号状态,线程1执行;又由于线程1释放后,hEvent仍旧处于有信号状态,所以线程2也执行了。

再修改:在线程1中,添加ResetEvent(hEvent)(手动设置事件为无信号状态),则线程2不会执行。

测试4:

bManualReset:FALSE
bInitialState:FALSE

hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);//线程释放后自动重置为无信号状态,初始化时为无信号状态

example4.cpp

[cpp]
view plain copy

  1. include “iostream”

  2. include “windows.h”

  3. using namespace std;
  4. DWORD WINAPI ThreadProc1(LPVOID lpParam);
  5. DWORD WINAPI ThreadProc2(LPVOID lpParam);
  6. HANDLE hEvent = NULL;
  7. HANDLE hThread1 = NULL;
  8. HANDLE hThread2 = NULL;
  9. int main(int argc, char *args[])
  10. {
  11. hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  12. if (SetEvent(hEvent))
  13. {
  14. cout <<“setEvent 成功” <
  15. }
  16. hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, NULL, 0,NULL);
  17. Sleep(200);
  18. hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc2, NULL, 0,NULL);
  19. Sleep(200);
  20. if ( NULL == hThread1)
  21. {
  22. cout <<“create thread fail!”;
  23. }
  24. return 0;
  25. }
  26. DWORD WINAPI ThreadProc1(LPVOID lpParam)
  27. {
  28. cout <<“in thread1@!”<
  29. DWORD dReturn = WaitForSingleObject(hEvent,INFINITE);
  30. if ( WAIT_OBJECT_0 == dReturn)
  31. {
  32. cout <<” thread1 signaled ! “<
  33. }
  34. cout <<“in thread1 –signal”<
  35. return 0;
  36. }
  37. DWORD WINAPI ThreadProc2(LPVOID lpParam)
  38. {
  39. cout <<“in thread2@!”<
  40. DWORD dReturn = WaitForSingleObject(hEvent,INFINITE);
  41. if ( WAIT_OBJECT_0 == dReturn)
  42. {
  43. cout <<“thread2 signaled ! “<
  44. }
  45. cout <<“in thread2–signal”<
  46. return 0;
  47. }

c++中CreateEvent函数

由于调用SetEvent,hEvent为有信号状态,线程1正常执行,又由于调用完线程1后,hEvent自动重置为无信号状态,所以线程2只能在等待,直到主线程退出。

修改:线程1中的SetEvent(hEvent);的注释去掉,再运行,则线程1和线程2 都会执行。

Original: https://www.cnblogs.com/lancidie/p/14499326.html
Author: oayx
Title: c++中CreateEvent函数

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/535560/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • C++设计模式(转载)

    C++设计模式之Adapter一、功能 将一个类的接口转换成客户希望的另外一个接口,解决两个已有接口之间不匹配的问题。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类…

    C++ 2023年5月29日
    092
  • vscode c++插件与配置

    1 本地运行 c/c++ –代码包 code runner –运行包 –C, C++, Java, JS, PHP, Python, Perl,…

    C++ 2023年5月29日
    089
  • c++ string 和wstring 之间的互相转换函数

    #include <string> std::string ws2s(const std::wstring& ws) { std::string curLoca…

    C++ 2023年5月29日
    060
  • c++实训课

    程序一: include 程序二: include 程序三: include Original: https://www.cnblogs.com/duanqibo/p/164138…

    C++ 2023年5月29日
    059
  • 聊聊 C# 和 C++ 中的 泛型模板 底层玩法

    最近在看 C++ 的方法和类模板,我就在想 C# 中也是有这个概念的,不过叫法不一样,人家叫 模板,我们叫 泛型,哈哈,有点意思,这一篇我们来聊聊它们底层是怎么玩的? 一:C++ …

    C++ 2023年5月29日
    044
  • [C++]一份Linq to object的C++实现

    几个月的构想+0.5小时的设计+4小时的linq.h编码+3小时的测试编码。 大量使用C++11的特性,在GCC 4.7.2下编译通过。 关于实现相关的描述就不说了,我表达能力差,…

    C++ 2023年5月29日
    052
  • c++构造和析构异常

    C++ 构造函数的异常是一个比较难缠的问题,很多时候,我们可能不去考虑这些问题,如果被问到,有人可能会说使用RAII管理资源。 但你真的考虑过如果构造函数失败了,到底会发生什么吗,…

    C++ 2023年5月29日
    053
  • The main difference between Java & C++(转载)

    C++ supports pointers whereas Java does not pointers. But when many programmers questioned…

    C++ 2023年5月29日
    071
  • Fixed width integer types (since C++11)

    越界问题非常频繁地困扰着开发人员 CPP常用的类型定义不能体现数据的bit位数,让开发人员非常抓狂,相信很多人都遇到过,当判定一个数值是否越界时候,一定是先去网上查表, 但是数据类…

    C++ 2023年5月29日
    077
  • Delphi及C++Builder经典图书一览表(持续更新中2018.01.02)

    序号 书名 原版书名 作者 译者 出版社 页数 年代 定价 备注 1 C++Builder 5程序设计大全 C++Builder 5 Developer’s Guide…

    C++ 2023年5月29日
    040
  • C+++string类如何判断字符串为空

    string类是C++STL类之一,有很丰富的接口。 string类为空,实际也就是元素为0个。 可以按照如下方式判断: 1、string类有自己的成员函数empty, 可以用来判…

    C++ 2023年5月29日
    071
  • UNITY 手游(安卓)如何使用C/C++代码

    解决方案:将C/C++代码编译成so供C#代码调用。 SO生成工具:android studio,简称AS 一,so 生成方法: 1,菜单:File->New->New…

    C++ 2023年5月29日
    087
  • C++11 并发指南七(C++11 内存模型一:介绍)

    第六章主要介绍了 C++11 中的原子类型及其相关的API,原子类型的大多数 API 都需要程序员提供一个 std::memory_order(可译为内存序,访存顺序) 的枚举类型…

    C++ 2023年5月29日
    059
  • C++ *和&

    概述 在c++中,当申明变量int *p 的时,表示p是一个储存地址的变量;比如int _p=0,表示p指向地址为00000000的地址单元。当申明指针p之后,再用_p表示p指向的…

    C++ 2023年5月29日
    067
  • 2.设计模式-七大原则(C++)

    任何一个设计模式都离不开七大原则中的任一原则.所以七大原则非常重要,只要我们明白了七大原则,就可以知道如何在项目中使用什么设计原则了. 设计模式的七大原则如下所示: 1.单一职责原…

    C++ 2023年5月29日
    057
  • C++源码—lock_guard

    在 C++11 中,我们可以使用 mutex 来实现线程的同步,mutex 包括上锁和解锁两个步骤。 lock_guard 的功能也是实现线程同步,可以进一步偷懒以及避免在锁定期间…

    C++ 2023年5月29日
    042
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球