(转)内核线程对象--Event事件对象
在所有的内核对象中,事件内核对象是个最基本的对象。事件能够通知一个操作已经完成。
客户机和一个服务器,它们之间需要互相进行通信例子(vs2008 )
事件内核对象的组成
一个使用计数(与所有内核对象一样),
一个用于指明该事件是个自动重置的事件还是一个人工重置的事件的布尔值,
一个用于指明该事件处于已通知状态还是未通知状态的布尔值。
有两种不同类型的事件对象
一种是人工重置的事件,另一种是自动重置的事件。
当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。
当自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
当一个线程执行初始化操作,然后通知另一个线程执行剩余的操作时,事件使用得最多。事件初始化为未通知状态,然后,当该线程完成它的初始化操作后,它就将事件设置为已通知状态。这时,一直在等待该事件的另一个线程发现该事件已经得到通知,因此它就变成可调度线程。这第二个线程知道第一个线程已经完成了它的操作。
用CreateEvent函数创建事件内核对象
HANDLE CreateEvent(
PSECURITY_ATTRIBUTES psa,
BOOL fManualReset,
BOOL fInitialState,
PCTSTR pszName
);
内核对象的操作技巧见前面相关章节,比如,如何设置它们的安全性,如何进行使用计数,如何继承它们的句柄,如何按名字共享对象等。
fMannualReset参数是个布尔值,它能够告诉系统是创建一个人工重置的事件(TRUE)还是创建一个自动重置的事件(FALSE)。
fInitialState参数用于指明该事件是要初始化为已通知状态(TRUE)还是未通知状态(FALSE)。当系统创建事件对象后, createEvent就将与进程相关的句柄返回给事件对象。
其他进程中的线程可以获得对该对象的访问权,方法是使用在pszName参数中传递的相同值(见:命名对象),使用继承性,使用DuplicateHandle函数等来调用CreateEvent,或者调用OpenEvent ,在pszName参数中设定一个与调用CreateEvent时设定的名字相匹配的名字:
HANDLE OpenEvent(
DWORD fdwAccess,
BOOL fInherit,
PCTSTR pszName
);
与所有情况中一样,当不再需要事件内核对象时,应该调用CloseHandle函数。
一旦事件已经创建,就可以直接控制它的状态
当调用SetEvent时,可以将事件改为已通知状态:
BOOL SetEvent(HANDLE hEvent);
当调用ResetEvent函数时,可以将该事件改为未通知状态:
BOOL ResetEvent(HANDLE hEvent);
事件成功等待的副作用
自动重置的事件:自动重置到未通知状态(所以通常没有必要为自动重置的事件调用ResetEvent函数)。所以他的名字才有自动两字。
人工重置的事件: Microsoft没有为人工重置的事件定义成功等待的副作用。所以它才叫人工。
简单例子,如何使用事件内核对象对线程进行同步
这个例子清楚地展示出使用人工重置事件与自动重置事件之间的差别。
// Create a global handle to a manual-reset, nonsignaled event.
HANDLE g_hEvent;
int WINAPI WinMain(...)
{
// Create the manual-reset, nonsignaled event.
g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //人工
// Spawn 3 new threads.
HANDLE hThread[3];
DWORD dwThreadID;
hThread[0] = _beginthreadex(NULL, 0, WordCount, NULL, 0, &dwThreadID);
hThread[1] = _beginthreadex(NULL, 0, SpellCheck, NULL, 0, &dwThreadID);
hThread[2] = _beginthreadex(NULL, 0, GrammarCheck, NULL, 0, &dwThreadID);
OpenFileAndReadContentsIntoMemory(...);
//Allow all 3 threads to access the memory.
SetEvent(g_hEvent); // 将事件设置已通知状态
...
}
DWORD WINAPI WordCount(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
return(0);
}
DWORD WINAPI SpellCheck(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
return(0);
}
DWORD WINAPI GrammarCheck(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
return(0);
}
当这个进程启动时,它创建一个人工重置的未通知状态的事件,并且将句柄保存在一个全局变量中。这使得该进程中的其他线程能够非常容易地访问同一个事件对象。现在3个线程已经产生。这些线程要等待文件的内容读入内存,然后每个线程都要访问它的数据。一个线程进行单词计数,另一个线程运行拼写检查器,第三个线程运行语法检查器。这3个线程函数的代码的开始部分都相同,每个函数都调用WaitForSingleObject,这将使线程暂停运行,直到文件的内容由主线程读入内存为止。
一旦主线程将数据准备好,它就调用SetEvent,给事件发出通知信号。这时,系统就使所有这3个辅助线程进入可调度状态,它们都获得了CPU时间,并且可以访问内存块。注意,这3个线程都以只读方式访问内存。这就是所有3个线程能够同时运行的唯一原因。还要注意,如果计算机上配有多个CPU,那么所有3个线程都能够真正地同时运行,从而可以在很短的时间内完成大量的操作。
如果这里使用自动重置的事件而不是人工重置的事件,那么应用程序的行为特性就有很大的差别。当主线程调用SetEvent之后,系统只允许一个辅助线程变成可调度状态。同样,也无法保证系统将使哪个线程变为可调度状态。其余两个辅助线程将继续等待。
已经变为可调度状态的线程拥有对内存块的独占访问权。让我们重新编写线程的函数,使得每个函数在返回前调用SetEvent函数(就像WinMain函数所做的那样)。这些线程函数现在变成下面的形式:
DWORD WINAPI WordCount(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
SetEvent(g_hEvent);
return(0);
}
DWORD WINAPI SpellCheck(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
SetEvent(g_hEvent);
return(0);
}
DWORD WINAPI GrammarCheck(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
SetEvent(g_hEvent);
return(0);
}
当线程完成它对数据的专门传递时,它就调用SetEvent函数,该函数允许系统使得两个正在等待的线程中的一个成为可调度线程。同样,我们不知道系统将选择哪个线程作为可调度线程,但是该线程将进行它自己的对内存块的专门传递。当该线程完成操作时,它也将调用SetEvent函数,使第三个即最后一个线程进行它自己的对内存块的传递。注意,当使用自动重置事件时,如果每个辅助线程均以读/写方式访问内存块,那么就不会产生任何问题,这些线程将不再被要求将数据视为只读数据。
BOOL PulseEvent(HANDLE hEvent);
PulseEvent函数使得事件变为已通知状态,然后立即又变为未通知状态,这就像在调用SetEvent后又立即调用ResetEvent函数一样。如果在人工重置的事件上调用PulseEvent函数,那么在发出该事件时,等待该事件的任何一个线程或所有线程将变为可调度线程。如果在自动重置事件上调用PulseEvent函数,那么只有一个等待该事件的线程变为可调度线程。如果在发出事件时没有任何线程在等待该事件,那么将不起任何作用。
PulseEvent函数并不非常有用(可以先不管它)。
原文地址:http://www.cnblogs.com/fangyukuan/archive/2010/09/04/1817750.html
(转)内核线程对象--Event事件对象的更多相关文章
- Python多线程-Event(事件对象)
Event 事件对象管理一个内部标志,通过set()方法将其设置为True,并使用clear()方法将其设置为False.wait()方法阻塞,直到标志为True.该标志初始为False. 方法: i ...
- trigger()的event事件对象之坑
问题引入,先贴一段有问题的代码,如果你对 trigger() 这个函数了解不透彻,还真看不出这段代码错在哪.完成的功能是样式转换器,想让页面在加载后自行触发点击事件隐藏三个按钮,但是效果如图并没有隐 ...
- 简单总结焦点事件、Event事件对象、冒泡事件
每学习一些新的东西,要学会复习,总结和记录. 今天来简单总结一下学到的几个事件:焦点事件.Event事件对象.冒泡事件 其实这几个事件应该往深的说是挺难的,但今天主要是以一个小菜的角度去尝试理解一些基 ...
- 第53天:鼠标事件、event事件对象
-->鼠标事件-->event事件对象-->默认事件-->键盘事件(keyCode)-->拖拽效果 一.鼠标事件 onclick ---------------鼠标点击事 ...
- vue 笔记,ref 及 $event 事件对象
本文仅用作简单记录 ref : 在标签上添加 ref = “name” ,表示获取当前元素节点 <input type="text" ref="info" ...
- event事件对象
事件对象event: 在触发DOM事件的时候都会产生一个对象 1.type:获取事件类型 2.target:获取事件目标 3.stopPropagation():组织事件冒泡 4.preventDef ...
- event事件对象和clientX,clientY
一.event : 事件对象 , 当一个事件发生的时候,和当前这个对象发生的这个事件有关的一些详细的信息都会被临时保存到一个指定地方-event对象,供我们在需要的调用.如:飞机-黑匣子 事件对象必须 ...
- jquery之event与originalEvent的关系、event事件对象用法浅析
在jquery中,最终传入事件处理程序的 event 其实已经被 jQuery 做过标准化处理, 其原有的事件对象则被保存于 event 对象的 originalEvent 属性之中, 每个 even ...
- 【js】event(事件对象)详解
1.事件对象 Event 对象代表事件的状态,比如事件在其中发生的元素.键盘按键的状态.鼠标的位置.鼠标按钮的状态. 什么时候会产生Event 对象呢? 例如: 当用户单击某个元素的时候,我们给这个元 ...
随机推荐
- 高级复制实验配置添加复制节点操作时报错:ORA-23308: object GP.T does not exist or is invalid
出错原因: 使用高级复制时,在源端启动复制支持,执行语句:REPADMIN@bys1>execute dbms_repcat.generate_replication_support('gp', ...
- 【解决方法】You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE)
出现场景: 正常调试是没有问题的,但是在Archive的时候,报出了这个错误. 问题详情: (null): URGENT: all bitcode will be dropped because ‘x ...
- C#中数组、ArrayList和List三者的区别(转)
好东西,总结的很到位,收藏了! 源地址:http://blog.csdn.net/zhang_xinxiu/article/details/8657431
- oracle 获取系统时间(转)
Oracle中如何获取系统当前时间 select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual; ORACLE里获取一个时间的年.季. ...
- MySQL 开放局域网
局域网连接mysql报错: ERROR 1130: Host '192.168.0.220' is not allowed to connect to this MySQL server 解决方法: ...
- ACM比赛
Description A soldier wants to buy w bananas in the shop. He has to pay k dollars for the first bana ...
- C++内联函数、函数模板之于头文件
一.基本说明 C++标准中提到,一个编译单元是指一个.cpp文件以及它所include的所有.h文件,.h文件里的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件 ...
- 理解Python的with as语句
简单的说, with open(filepath, 'wb') as file: file.write("something") 等价于: file = open(filepath ...
- 二、Python-----用户交互
1.用户交互 Python 3.0的写法 name = input("Please input your name:") Python 2.0的写法 name = raw_inpu ...
- [LeetCode]题解(python):007-Reverse Integer
题目来源: https://leetcode.com/problems/reverse-integer/ 题意分析: 这道题目很简单,就是将一个数反转,123变321,-123变321. 题目思路: ...