多线程 -- 等待函数、事件内核对象
来源:互联网 发布:软件行业研究报告 编辑:程序博客网 时间:2024/06/12 13:14
用内核对象进行线程同步
内核对象:Windows操作系统使用内核对象来管理进程、线程、文件等诸多种类的大量资源。内核对象的创建通常是通过Windows API,比如
CreateThread将创建一个线程内核对象,并返回一个内核对象句柄。内核对象实际上是一小块内存,其中包括了引用计数、安全性描述等信息,操作系统通
过这一小段内存来管理对应的内核资源。内核对象的实际内存地址并非句柄所展示的,它们在进程内的内核对象句柄表中有映射。
在前几篇中,介绍了在用户模式下的线程同步机制:InterLocked系列、关键段、Slim读写锁。这些同步机制可以在进行线程同步的同时让线程保持在用户模式下。然而用户
模式下的线程同步机制有时不能满足我们的要求。从这篇开始,将介绍使用内核对象进行线程同步。在考虑是使用用户模式的同步机制还是使用内核对象来同步的时候,需要综
合考量,尽量使用用户模式的线程同步机制。
内核对象普遍存在两种状态,要么是触发,要么是未触发。每种内核对象在这两个状态间切换过程都有其特殊的特点,比如进程内核对象在创建的时候总是处于未触发状态,当
进程终止时,会变成触发状态;而且进程内核对象永远不会从触发态变回未触发态。于是,如果我们的线程需要等待子进程终止时才继续,那么可以将线程进入等待状态,当子
进程标识的进程内核对象变成触发状态的时候唤醒线程!我们所需要的仅仅是Windows为我们提供的等待函数。
等待函数
等待函数能够是一个线程进入等待状态,直到指定的内核对象被触发为止。这些等待函数有:
DWORD
WINAPI WaitForSingleObject(
__in
HANDLE
hHandle,
__in
DWORD
dwMilliseconds
);
当线程调用WaitForSingleObject的时候,第一个参数hObject用来标识内核对象,第二个参数是个超时时间(传入INFINITE表示永远等待直到触发)。
DWORD
WINAPI WaitForMultipleObjects(
__in
DWORD
nCount,
__in
const
HANDLE
*lpHandles,
__in
BOOL
bWaitAll,
__in
DWORD
dwMilliseconds
);
WaitForMultipleObjects允许调用线程检查多个内核对象的触发状态。
使用等待函数有时是会改变内核对象的状态的。比如:线程正在等待一个自动重置事件对象,当事件对象被触发的时候,函数会检测到这一情况并返回调用线程,但是在返回之
前,他会使事件变为非触发状态。等待函数在不同的内核对象上调用并返回所引起的这样类似的“副作用”是不同的。在对内核对象展开介绍后,将看到这一点。
如果多个线程在同时等待同一个内核对象,那么任何一个线程都有可能被唤醒。我们不应该做出类似“谁先等待谁就先唤醒”这样的假设。
接下来,将分几篇的内容分别介绍那些与线程同步有关的内核对象。
事件内核对象
事件内核对象分为手动重置和自动重置,区别在于当对象从未触发状态变成触发状态后,会不会自动重置回未触发状态。与其他内核对象相同,事件内核对象也包括引用计数。
下面的函数CreateEvent用以创建事件内核对象:
HANDLE
CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL
bManualReset,
BOOL
bInitialState,
LPTSTR
lpName
);
lpEventAttributes:会被忽略,必须为NULL(这里是MSDN的说法,在Windows Via C/C++中,暗示了这个参数与内核对象的安全属性和共享特性有关。不过通常都会
传入NULL,因为不太会考虑让一个事件对象变为可继承)
bManualReset:手动重置(TRUE)还是自动重置(FALSE)
bInitialState:初始状态为触发(TRUE)还是非触发(FALSE)
lpName:用于共享内核对象的机制,这里与线程同步无关,不再阐述,传入NULL即可。
返回值:事件对象的句柄
Windows Vista还支持下面这个函数CreateEventEx来创建事件内核对象,详情请参见MSDN:
HANDLE
WINAPI CreateEventEx(
__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,
__in_opt
LPCTSTR
lpName,
__in
DWORD
dwFlags,
__in
DWORD
dwDesiredAccess
);
我们使用下面的函数来控制事件对象的状态:
BOOL
SetEvent(
HANDLE
hEvent
);
//将内核对象设置为触发状态
BOOL
ResetEvent(
HANDLE
hEvent
);
//将内核对象设置为非触发状态
BOOL
PulseEvent(
HANDLE
hEvent
);
//触发内核对象并立即将其重置为未触发状态,会唤醒正在等待的线程
如果用图来表示他们的作用就很直观了:
另外OpenEvent通常用于进程同步,但前提是事件内核对象必须有别名(通过给某些内核对象起别名,是一种共享内核对象的方式):
HANDLE
OpenEvent(
DWORD
dwDesiredAccess,
BOOL
bInheritHandle,
LPCTSTR
lpName
);
下图描述了事件内核对象的示例用法(同一进程内):
主线程先创建一个事件内核对象,并创建两个线程,这两个线程的执行需要依赖主线程的准备工作,因此调用WaitForSingleObject等待事件对象触发。主线程完成准备工作
后,调用SetEvent使对象变成触发状态,这时两个子线程将被唤醒开始执行代码。
在后面的篇章中,将继续介绍其他可以用来线程同步的内核对象。
出处:http://www.cnblogs.com/P_Chou/archive/2012/07/03/waitobject-and-event-in-thread-sync.html
- 多线程 -- 等待函数、事件内核对象
- 多线程 -- 可等待的计时器内核对象
- 【Windows】线程漫谈——线程同步之等待函数和事件内核对象
- -【内核对象线程同步】等待函数
- 白话windows多线程同步之可等待计时器内核对象
- 多线程事件等待
- 多线程锁:事件内核对象(进程锁)
- 等待定时器内核对象
- 多线程系列之——事件内核对象
- 多线程学习篇(三)事件内核对象
- ucosIII 事件标志组、同时等待多个内核对象、存储管理
- 线程同步——内核对象(互斥、事件、信号量、可等待计时器)
- win32多线程等待消息函数
- 多线程并发访问,等待同一事件退出。
- C#多线程同步事件及等待句柄
- C#多线程同步事件及等待句柄
- C#多线程同步事件及等待句柄
- C#多线程同步事件及等待句柄 .
- 十进制转换为N进制问题
- 关于CLOSE BY CLIENT STACK TRACE
- 自动布局框架介绍
- NGUI系列教程五(角色信息跟随)
- 掀开C#的一层面纱
- 多线程 -- 等待函数、事件内核对象
- 二叉树的层次遍历
- CentOS上使用OpenStack的一些问题
- POJ 1241
- Java Reflection Tutorial for Classes, Methods, Fields, Constructors, Annotations and much more
- stochastic regression
- 从服务器获取时间的年月日三级联动
- slf4j+log4j的初次使用
- 条款 22: 尽量用“传引用”而不用“传值”