本书首先介绍了一个重要的概念“成功的副作用”,这里笔者作一下简述。

  当调用WaitForSingleObject和WaitForMultipleObject函数成功之后,该函数在返回成功的时候,系统可能会自动更改所等待的内核对象的状态,即将其从“已通知状态”切换为“未通知状态”。

  当一个内核对象的状态被更改,称之为“成功等待的副作用”。比如,一个“自动重置”的事件内核对象,当调用等待函数成功返回的时候,该事件内核对象会由已通知状态转变为未通知状态。

  比如此时有一个自动重置的事件内核对象hEvent,它处于未通知状态。线程T1、T2、T3内部调用“WaitForSingleObject(hEvent, INFINITE);”,这样当该事件内核对象变为“已通知”状态的话,T1线程“可能”被唤醒,但是其他的线程T2和T3呢?由于在T1线程内部WaitForSingleObject函数返回成功,又将hEvent事件内核对象设置为“未通知”状态,那么T2和T3就不可能被唤醒。

  也就是说,“成功等待的副作用”会导致多个等待在同一个内核对象上的线程只能被唤醒一个。

  好,下面我们来讨论“事件内核对象”。

  在所有内核对象中,事件内核对象是最基本的一个内核对象。在事件内核对象内部,有以下几个比较重要的数据:

1、有一个“引用计数”:指明被打开的次数;

2、一个“布尔值”:指明该事件内核对象是自动重置的还是人工重置的;

3、另一个“布尔值”:指明该事件内核对象是“已通知状态”还是“未通知状态”。

  事件内核对象可以通知一个事件已经完成。有两种不同的类型:自动重置和人工重置。当人工重置的事件内核对象得到通知的时候,所有等待在事件内核对象上的线程都变成可调度线程。当一个自动重置的事件内核对象得到通知的时候,等待在该事件内核对象上的线程只有一个能变成可调度状态。

  要使用事件内核对象,首先调用CreateEvent函数来创建一个事件内核对象:

HANDLE CreateEvent(
   PSECURITY_ATTRIBUTES psa,
   BOOL bManualReset,
   BOOL bInitialState,
   PCTSTR pszName);

  参数psa是一个SECURITY_ATTRIBUTES(安全属性)结构的指针,一般设置为默认安全,传递NULL。

  bManualReset参数指定了该内核对象是人工重置(传递TRUE)的还是自动重置(传递FALSE)的。

  bInitialState参数指定了该内核对象起始状态是已通知(传递TRUE)还是未通知状态(FALSE)。

  pszName参数为要创建的事件内核对象起一个名字,如果传递NULL,则创建一个“匿名”的事件内核对象。如果不传递NULL,且系统中已经存在该名字的事件内核对象,则不创建新的事件内核对象而是打开这个已经存在的,返回它的句柄。

  该函数如果成功,返回事件内核对象的句柄,这样就可以操纵它了。如果失败,返回NULL。

  Windows Vista提供了另一个函数来创建事件内核对象:

HANDLE CreateEventEx(
   PSECURITY_ATTRIBUTES psa,
   PCTSTR pszName,
   DWORD dwFlags,
   DWORD dwDesiredAccess);

  该函数的psa和pszName参数的意义和函数CreateEvent相同。

  参数dwFlags可以有以下数据的“位或组合”:

WinBase.h中定义的位组合数据

描述

CREATE_EVENT_INITIAL_SET (0x00000002)

如果设置了该数据,则表明事件内核对象的起始状态为已通知状态;否则起始状态为未通知状态。

CREATE_EVENT_MANUAL_RESET (0x00000001)

如果设置了该数据,则表明事件内核对象是人工重置的;否则为自动重置的。

  参数dwDesiredAccess可以让你对该事件内核对象的访问加一些限制,本书没有细说,查MSDN就可以了吧。

  可以打开一个“命名”的事件内核对象:

HANDLE OpenEvent(
   DWORD dwDesiredAccess,
   BOOL bInherit,
   PCTSTR pszName);

  第一个参数指明的访问的限制,第二个参数表示该事件内核对象的句柄能够被子进程继承,第三个参数指明了该事件内核对象的名字。该函数成功返回事件内核对象的句柄,失败返回NULL。

  当不需要使用这些句柄时,需要调用CloseHandle函数来递减内核对象的引用计数,使得该内核对象可以被及时清除。

  当一个事件内核对象被创建之后,你可以直接控制它的状态。你可以通知它,使得它从未通知状态转变为已通知状态:

BOOL SetEvent(HANDLE hEvent);

  也可以重新设置它,使它从已通知状态变为未通知状态:

BOOL ResetEvent(HANDLE hEvent);

  一个自动重置的事件内核对象,如果等待成功,由于“成功等待的副作用”机制会将该事件内核对象由已通知状态变为未通知状态,这个时候就没有必要调用ResetEvent函数了。

  如果是一个人工重置的事件内核对象,等待成功之后,并不会被设置为未通知状态,而是要程序员调用ResetRvent函数来使之转变为未通知状态。

  还有要注意的就是,一个“自动重置”的事件内核对象收到通知,转变为已通知状态的时候,最多只能唤醒“一个”等待在它上的线程。一个“人工重置”的事件内核对象收到通知,转变为已通知状态的时候,能够唤醒“所有”等待在它上的线程。

转载于:https://www.cnblogs.com/wz19860913/archive/2008/08/11/1265090.html

《Windows via C/C++》学习笔记 —— 内核对象的“线程同步”之“事件内核对象”...相关推荐

  1. Chapter09-内核模式下的线程同步之事件内核对象

    有两种事件内核对象:自动事件和手动事件.当手动事件被触发时,所以该事件的等待线程都编程可调度状态:而自动事件被触发时,只有个一个等待该事件线程变成可调度状态. 下面再逐个讲解Event的相关函数: a ...

  2. muduo学习笔记 - 第2章 线程同步精要

    第2章 线程同步精要 2.1 互斥器 (mutex) 互斥器保护了临界区,任何时刻最多只能有一个线程在mutex划出的临界区内活动 推荐使用原则: 用RAII手法封装mutex的创建.销毁.加锁.解锁 ...

  3. Windows驱动开发学习笔记(七)—— 多核同步内核重载

    Windows驱动开发学习笔记(七)-- 多核同步 基础知识 并发与同步 分析 InterlockedIncrement 原子操作相关API 内核文件 多核同步 临界区 示例一:错误的临界区 示例二: ...

  4. Windows事件等待学习笔记(二)—— 线程等待与唤醒

    Windows事件等待学习笔记(二)-- 线程等待与唤醒 要点回顾 等待与唤醒机制 可等待对象 可等待对象的差异 线程与等待对象 一个线程等待一个对象 实验 第一步:编译并运行以下代码 第二步:在Wi ...

  5. Windows进程与线程学习笔记(八)—— 线程切换与TSS/FS

    Windows进程与线程学习笔记(八)-- 线程切换与TSS/FS 要点回顾 线程切换与TSS 内核堆栈 调用API进0环 实验:分析SwapContext 线程切换与FS 段描述符结构 分析Swap ...

  6. [转]Windows平台下Makefile学习笔记

    Windows平台下Makefile学习笔记(一) 作者:朱金灿 来源:http://blog.csdn.net/clever101 决心学习Makefile,一方面是为了解决编译开源代码时需要跨编译 ...

  7. Windows进程与线程学习笔记(九)—— 线程优先级/进程挂靠/跨进程读写

    Windows进程与线程学习笔记(九)-- 线程优先级/进程挂靠/跨进程读写 要点回顾 线程优先级 调度链表 分析 KiFindReadyThread 分析 KiSwapThread 总结 进程挂靠 ...

  8. Windows进程与线程学习笔记(六)—— 线程切换

    Windows进程与线程学习笔记(六)-- 线程切换 主动切换 分析KiSwapContext 分析SwapContext 分析KiSWapThread 总结 时钟中断切换 系统时钟 分析INT 0x ...

  9. oracle查询数据做标记,【学习笔记】Oracle如何使用dbms_shared_pool.markhot标记热对象...

    [学习笔记]Oracle如何使用dbms_shared_pool.markhot标记热对象 时间:2016-10-30 20:17   来源:Oracle研究中心   作者:HTZ   点击: 次 天 ...

  10. Windows核心编程:第9章 用内核对象进行线程同步

    Github https://github.com/gongluck/Windows-Core-Program.git //第9章 用内核对象进行线程同步.cpp: 定义应用程序的入口点. //#in ...

最新文章

  1. 一键安装python3环境
  2. Codepen 每日精选(2018-4-22)
  3. python json转换字典_Python json转字典字符方法实例解析
  4. P2280 [HNOI2003]激光炸弹
  5. 【数字逻辑设计】判断二进制加法溢出的电路设计
  6. uva 10048 Audiophobia(最小生成树)
  7. Akka的Actor生命周期《Eight》译
  8. 笔记_pytorch
  9. 程序批量将文本文件中的某字符替换
  10. 二元函数对xy同时求导_《高等数学》微课视频“二元函数的全微分求积”录音...
  11. 在线股票配资配资股票交易整站源码/牛股跟投带实盘策略区块链网站整站源码
  12. 中国眼下拥有的人造卫星的种类及其作用
  13. 小程序自动定位当前位置
  14. 强化学习蘑菇书Easy RL第一章
  15. android 支付宝sdk接入详解
  16. matlab lpc求共振峰频率,共振峰检测算法研究与实现
  17. 光纤收发器测试方法大全
  18. sql基础_SQL基础
  19. 撬动PMBOK6运用指南第九章
  20. Python爬虫入门实战,图文详细教学,一看就懂

热门文章

  1. 阿里45K高级Java岗,必备技能清单
  2. “深入浅出”是什么导致不能以操作系统用户身份连接到数据库
  3. Linux 命令学习(1): head和tail
  4. 结构体内存对齐的原则及原理
  5. Java基础--序列化和反序列化
  6. 汉字与区位码互转(转)
  7. [ios]object-c math.h里的数学计算公式介绍
  8. flash位图技术研究篇(3):移动缓冲区域
  9. iOS swift 建立桥接文件及更改位置
  10. Sqlserver 索引