事件,在我看来就是一种触发机制,即满足某一条件的触发。当线程需要等待某一事件的发生而不是一个资源的解锁,这在接收网络信息包或等待一个已完成某些任务的线程发出信号时非常有用。在Win32系统中,提供了事件对象。事件对象是同步对象中最简单的形式,也是最具有弹性的同步机制。其与互斥量和信号量的区别在于:互斥量和信号量是用于对数据的访问的,而事件是用来发信号表示某一操作已经完成了。事件对象是一种核心对象,它的惟一目的就是成为激发状态或未激发状态,这两种状态完全由程序来控制,不会成为等待函数的副作用。
有两种事件对象:一、人工重置。其作用是向几个线程同时发信号,表示某一操作已经完成;二、自动重置。其作用是向一个线程发信号,表示某一操作已经完成。
线程常用用途:事件最常用于一个线程进行初始化工作后,发信号给另一个线程,让其完成剩余的工作。初始化线程将事件设置为无信号状态后开始进行初始化,而后,当初始化完成后,线程把事件设置为有信号状态。当工作线程开始工作时,它立即自我挂起,等待事件变为有信号。当初始化线程把事件设置为有信号状态后,工作县城就醒来执行余下的必要工作。
例如,一个线程运行了两个线程。第一个线程从文件中读取数据到内存缓冲区,在数据读完后,它就发信号给第二个线程告诉它可以处理数据了。当第二个线程完成了对数据的处理后,它就需要再给第一个线程发信号,以便使第一个线程能从文件中读取下一块数据。
Win32 API产生事件对象的函数原型如下:
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
该函数可以用来创建一个事件对象,也可以用来打开一个已存在的事件对象句柄。在函数调用后立即调用GetLastError()函数,如果返回是ERROR_ALREADY_EXISTS,则说明调用打开一个现有的事件。
打开已存在事件对象的句柄还可以调用以下原型:
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
关闭事件对象,调用CloseHandle()函数。用户必须为每个CreateEvent()或OpenEvent()函数调用一个CloseHandle()函数。
为了将事件对象设置为有信号状态,调用SetEvent()和PulseEvent()函数,这两个函数分别描述如下:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
这两个函数都接受一个事件对象的句柄。SetEvent()函数并不将事件重置为无信号状态,对自动重置事件,SetEvent()只解锁一个在该事件上等待的线程。,WaitForSingleObject()或其他等待函数自动将事件重置为无信号状态。对人工重置事件,SetEvent()解锁在该事件上等待的所有线程,即当人工重置事件变为有信号后,所有等待该事件的线程都被允许运行了,它将保持有信号状态,直到某个线程显式地重置该事件。
PulseEvent()将事件标识为有信号状态并重置事件,它相当于连续执行3步骤:调用SetEvent()、释放等待事件、在立即调用ResetEvent()函数。当PulseEvent()返回时,时间仍留在无信号状态。对人工重置事件,PulseEvent()解锁在事件上等待的所有线程。对自动事件,PulseEvent()只解锁一个线程。
要显式(人工)地重置一个事件,调用如下函数:
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)