(转)内核线程对象--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

时间: 2024-09-28 16:33:03

(转)内核线程对象--Event事件对象的相关文章

JavaScript中的Event事件对象详解

JavaScript事件[event] 在JavaScript中对于事件来讲,首先,我们需要了解这样几个概念:事件:事件处理程序:事件类型:事件流:事件冒泡:事件捕获:事件对象:浏览器内核:事件绑定:事件方面的性能优化(事件委托.移除事件处理程序):常见的浏览器兼容问题等. 什么是事件event: JavaScript事件是:浏览器.文档(document)窗口中的发生的特定的交互瞬间:而JavaScript和HTML之间的交互行为就是通过事件来触发的. 事件处理程序: 事件处理程序:我们用户在

VC++深入详解——16章:线程同步,事件对象

这章介绍另外:事件对象和关键代码段. 进程相关函数: CreateEvent函数: 第一个参数:安全属性,默认的安全属性为NULL 第二个参数:复位方式, 人工设置为TRUE,自动设置为FALSE, 当为人工设置时,等待事件的线程时,需要resetevent函数来设置其为无型号状态. 第三个参数:初始状态:TRUE为有信号状态,FALSE为无信号状态. 第四个参数:对象名称,NULL为匿名名称. 创建或打开一个命名或匿名的事件对象(也属于内核对象) 返回:返回的是事件对象的句柄. SetEven

trigger()的event事件对象之坑

问题引入,先贴一段有问题的代码,如果你对 trigger()  这个函数了解不透彻,还真看不出这段代码错在哪.完成的功能是样式转换器,想让页面在加载后自行触发点击事件隐藏三个按钮,但是效果如图并没有隐藏按钮们:控制台会报错: target  属性是 undefined ,肯定是 event 这个事件对象没获取到的问题,程序到17行出错停止,这让我感到疑问:自定义触发的事件难道没有event对象吗?. 1 <div id="switcher" class="switche

笔记-【3】-event事件对象的详解!

event事件对象:是指当前对象发生的事件的一些详细的信息在event这个对象里. event对象从哪里来?从事件函数中传入 obj. //e就会当前的事件对象event } 对象就有属性和方法:那么event对象也有属性和方法 event的属性和方法: { 属性: button :  当前事件的方法中判断鼠标的按键位置 有三个值: 0 (左键) 1(滚轮) 2(右键) ctrlkey:  判断是否按下了ctrl键; altkey:  判断是否按下了alt键; shiftkey:  判断是否按下

简单总结焦点事件、Event事件对象、冒泡事件

每学习一些新的东西,要学会复习,总结和记录. 今天来简单总结一下学到的几个事件:焦点事件.Event事件对象.冒泡事件 其实这几个事件应该往深的说是挺难的,但今天主要是以一个小菜的角度去尝试理解一些基本的知识点. 1.焦点事件: 1.1概念理解: 想象场景:当一堆text文本框出现在面前,当点击其中一个文本框,它就会响应用户,并出现光标闪动(这时,点击令它获得焦点). 所以说:焦点事件是用来让浏览器区分哪一个对象是用户要进行操作(输入值.选择.跳转)的. 总结===>  浏览器(区分)哪一个对象

event事件对象

<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>无标题文档</title> <script> /* event : 事件对象 , 当一个事件发生的时候,和当前这个对象发生的这个事件有关的一些详细的信息都会被临时保存到一个指定

event事件对象和clientX,clientY

一.event : 事件对象 , 当一个事件发生的时候,和当前这个对象发生的这个事件有关的一些详细的信息都会被临时保存到一个指定地方-event对象,供我们在需要的调用.如:飞机-黑匣子 事件对象必须在一个事件调用的函数里面使用才有内容 事件函数:事件调用的函数,一个函数是不是事件函数,不在定义的决定,而是取决于这个调用的时候 兼容 ie/chrome : event是一个内置全局对象 标准下 : 事件对象是通过事件函数的第一个参数传入 如果一个函数是被事件调用的那么,这个函数定义的第一个参数就

jquery之event与originalEvent的关系、event事件对象用法浅析

在jquery中,最终传入事件处理程序的 event 其实已经被 jQuery 做过标准化处理, 其原有的事件对象则被保存于 event 对象的 originalEvent 属性之中, 每个 event 都是 jQuery.Event 的实例 其原型链中保存有六个方法,  代码如下 复制代码 jQuery.Event.prototype = {     preventDefault: function() {         // 取消事件默认行为     },     stopPropagat

js的event事件对象汇总

JavaScript事件对象是浏览器默认传入的,但是对于浏览器的兼容问题,我们需要对事件对象进行兼容.但是jQuery已经帮我们解决了所有兼容性的问题,并且给我们添加了很多有用的方法.已经是比较历史的问题了,给大家提供参考.1.event.target 获取绑定事件的DOM元素2.event.type 获取事件的类型3.event.data 获取事件中传递的数据4.event.pagX/pagY 获取根据页面原点的X,Y值5.event.screenX/screenY 获取根据显示器窗口的X,Y