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++的赋值构造函数(赋值运算符重载)

    当一个类的对象向该类的另一个对象赋值时,就会用到该类的赋值构造函数。 当没有重载赋值构造函数(赋值运算符)时,通过默认赋值构造函数来进行赋值操作 注意:这里a,b对象是已经存在的,…

    C++ 2023年5月29日
    063
  • 从三个语言(C++,Java,C#)的几个性能测试案例来看性能优化

    随着时间的发展,现在的虚拟机技术越来越成熟了,在有些情况下,Java,.Net等虚拟机密集计算的性能已经和C++相仿,在个别情况下,甚至还要更加优秀。本文详细分析几个性能测试案例,…

    C++ 2023年5月29日
    090
  • CLion之C++框架篇-安装工具,基础框架的搭建(一)

    背景 日常学习C++,也就是看看书、在vim里写写代码。在日常项目开发中,也是边看书(一是系统性理解、二是找找有什么更好的代码编写方式)边写代码,会顺带看看别人的代码怎么写的? 日…

    C++ 2023年5月29日
    088
  • Prim算法(二)之 C++详解

    普里姆(Prim)算法,是用来求加权连通图的最小生成树的算法。 基本思想对于图G而言,V是所有顶点的集合;现在,设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,T存放…

    C++ 2023年5月29日
    071
  • 对类的理解(c++)

    介绍目录: 1.类成员 1.1 成员函数 1.2 构造函数 1.2.1 对构造函数的理解 1.2.2成员初始化列表 1.2.3必须使用成员初始化列表的几种情况 1.2.4对于拷贝构…

    C++ 2023年5月29日
    078
  • C++矩阵运算库推荐

    最近在几个地方都看到有人问C++下用什么矩阵运算库比较好,顺便做了个调查,做一些相关的推荐吧。主要针对稠密矩阵,有时间会再写一个稀疏矩阵的推荐。 Armadillo:C++下的Ma…

    C++ 2023年5月29日
    079
  • c和c++开发工具之clion和vs

    个人体验结果 如果是CMake或者要跨平台的话,建议使用CLion 像我在看书写练习题的话,Clion使用cmake编译c/c++源码更简单上手使用。 如果项目不大,两者都可以。如…

    C++ 2023年5月29日
    0142
  • C++ 借助指针突破访问权限的限制,访问private、protected属性的成员变量(花拳绣腿)

    #include <iostream> using namespace std; class A { public: A(int a, int b, int c); p…

    C++ 2023年5月29日
    076
  • C++中 线程函数为静态函数 及 类成员函数作为回调函数

    线程函数为静态函数: 线程控制函数和是不是静态函数没关系,静态函数是在构造中分配的地址空间,只有在析构时才释放也就是全局的东西,不管线程是否运行,静态函数的地址是不变的,并不在线程…

    C++ 2023年5月29日
    071
  • C++智能指针原理

    简介 智能指针就是对指针进行封装,使其提供特有的功能。 unique_ptr:封装了原始指针使其只能在同一时刻被同一对象拥有,并且在离开作用域时会自动销毁。 shared_ptr:…

    C++ 2023年5月29日
    094
  • EclipseC++学习笔记-4 使用win11 wslg 启动应用

    wslg在win10下无法安装,升级win11后才可以基本按网上方法都能安装成功,但需要注意两点1、wsl –update2、如果启动程序不报错,但是不显示窗口的话 e…

    C++ 2023年5月29日
    060
  • C++ #ifndef、#define、#endif作用

    在C++项目中,#ifndef、#define、#endif非常常见,接下来就来简单说一下它们的作用。 作用:防止头文件被重复引用,防止被重复编译。 简介: ifndef 它是if…

    C++ 2023年5月29日
    0103
  • 腾讯研发类笔试面试试题(C++方向)(转)

    原文转自 https://www.cnblogs.com/freebird92/p/9595244.html 1、C和C++的特点与区别? 答: (1)C语言特点:1.作为一种面向…

    C++ 2023年5月29日
    064
  • C和C++混合编程中的extern “C” {}

    在用C++的项目源码中,经常会不可避免的会看到下面的代码: 它到底有什么用呢,你知道吗?而且这样的问题经常会出现在面试or笔试中。下面我就从以下几个方面来介绍它: 1、#ifdef…

    C++ 2023年5月29日
    076
  • c++ 数字类型转string

    include using namespace std; std::to_string(x) 几乎所有的数字类型都可以转 桂棹兮兰桨,击空明兮溯流光。 Original: http…

    C++ 2023年5月29日
    054
  • C++ 回调函数(CallBack)的用法分析

    本文实例分析了C++中回调函数(CallBack)的用法。分享给大家供大家参考。具体分析如下: 如果试图直接使用C++的成员函数作为回调函数将发生错误,甚至编译就不能通过。其错误是…

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