线程的同步互斥之事件对象(Event)
2015-08-21 17:09
585 查看
事件对象(Event Object),通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作。
事件包含一个使用计数(与所有内核对象一样),一个BOOL值(用于指明该事件是个自动重置的事件还是一个人工重置的事件),还有一个BOOL值(用于指明该事件处于已通知状态还是未通知状态)。事件能够通知一个线程的操作已经完成。有两种类型的事件对象。一种是人工重置事件,另一种是自动重置事件。他们不同的地方在于:当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
当一个线程执行初始化操作,然后通知另一个线程执行剩余的操作时,事件使用得最频繁。在这种情况下,事件初始化为未通知状态,然后,当该线程完成它的初始化操作后,它就将事件设置为已通知状态,而一直在等待该事件的另一个线程在事件已经被通知后,就变成可调度线程。
上面理论也是我抄别人的,感觉解释的很好,索性就用了。不多说,直接上代码了。
事件对象(Event Object)的具体使用步骤(个人总结):
1、调用CreateEvent函数创建一个事件对象;
2、调用WaitForSingleObject函数等待线程;
3、调用SetEvent设置事件为有标记;
4、线程中使用完后调用ReleaseEvent来释放事件对象;
其具体的用法还分为手动事件和自动事件来处理,上面的程序使用的自动事件。
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName );
功能:创建一个事件对象。
参数:lpEventAttributes,事件对象的安全属性,使用默认的就是NULL。
参数: bManualReset,创建的Event是自动事件还是人工事件。如果true,人工复位,一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复为无信号; 如果为false,Event被设置为有信号,则当有一个wait到它的Thread时,该Event就会自动复位,变成无信号。如果想在每次调用WaitForSingleObject 后让WINDOWS为您自动地把事件地状态恢复为无信号”状态,必须把该参数设为FALSE,否则,您必须每次调用ResetEvent函数来清除事件的信号。
参数:bInitialState,初始状态,true,有信号,false无信号
参数:lpName,事件对象的名称(也许在OpenEvent中需要使用此名称)。
返回值: 成功返回一个事件的句柄, 失败返回NULL。
BOOL WINAPI SetEvent(In HANDLE hEvent)
功能:将事件对象设置为有标记
参数:hEvent,事件对象的句柄
返回值:成功返回非0,失败返回0.
WaitForSingleObject函数在上一篇笔记已经解释,这里就不重复了。
上面的的事件对象使用的自动事件对象,如果想使用人工事件对象,可以将CreateEvent函数的第二个参数设置为true就可以。上面的事件对象是基本应用,其更多的用法可以去查询下PulseEvent这个函数,你会有更多发现。
事件包含一个使用计数(与所有内核对象一样),一个BOOL值(用于指明该事件是个自动重置的事件还是一个人工重置的事件),还有一个BOOL值(用于指明该事件处于已通知状态还是未通知状态)。事件能够通知一个线程的操作已经完成。有两种类型的事件对象。一种是人工重置事件,另一种是自动重置事件。他们不同的地方在于:当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
当一个线程执行初始化操作,然后通知另一个线程执行剩余的操作时,事件使用得最频繁。在这种情况下,事件初始化为未通知状态,然后,当该线程完成它的初始化操作后,它就将事件设置为已通知状态,而一直在等待该事件的另一个线程在事件已经被通知后,就变成可调度线程。
上面理论也是我抄别人的,感觉解释的很好,索性就用了。不多说,直接上代码了。
#include <iostream> #include <windows.h> using namespace std; DWORD WINAPI Thread1(LPVOID lpParmeter); DWORD WINAPI Thread2(LPVOID lpParmeter); static HANDLE g_hEvent = INVALID_HANDLE_VALUE; static int g_iCnt = 50; int main(int argc, char** argv) { HANDLE thread1 = INVALID_HANDLE_VALUE; HANDLE thread2 = INVALID_HANDLE_VALUE; g_hEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("Event")); if(!g_hEvent) { cout<<" Event fail!"<<endl; return -1; } thread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL); thread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL); SetEvent(g_hEvent); Sleep(4000); CloseHandle(thread1); CloseHandle(thread2); return 0; } DWORD WINAPI Thread1(LPVOID lpParmeter) { while(1) { WaitForSingleObject(g_hEvent, INFINITE); if(g_iCnt>0) { Sleep(20); cout<<"THread1:"<<g_iCnt--<<endl; SetEvent(g_hEvent); } else { SetEvent(g_hEvent); break; } } return 0; } DWORD WINAPI Thread2(LPVOID lpParmeter) { while(1) { WaitForSingleObject(g_hEvent, INFINITE); if(g_iCnt>0) { Sleep(20); cout<<"THread2:"<<g_iCnt--<<endl; SetEvent(g_hEvent); } else { SetEvent(g_hEvent); break; } } return 0; }
事件对象(Event Object)的具体使用步骤(个人总结):
1、调用CreateEvent函数创建一个事件对象;
2、调用WaitForSingleObject函数等待线程;
3、调用SetEvent设置事件为有标记;
4、线程中使用完后调用ReleaseEvent来释放事件对象;
其具体的用法还分为手动事件和自动事件来处理,上面的程序使用的自动事件。
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName );
功能:创建一个事件对象。
参数:lpEventAttributes,事件对象的安全属性,使用默认的就是NULL。
参数: bManualReset,创建的Event是自动事件还是人工事件。如果true,人工复位,一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复为无信号; 如果为false,Event被设置为有信号,则当有一个wait到它的Thread时,该Event就会自动复位,变成无信号。如果想在每次调用WaitForSingleObject 后让WINDOWS为您自动地把事件地状态恢复为无信号”状态,必须把该参数设为FALSE,否则,您必须每次调用ResetEvent函数来清除事件的信号。
参数:bInitialState,初始状态,true,有信号,false无信号
参数:lpName,事件对象的名称(也许在OpenEvent中需要使用此名称)。
返回值: 成功返回一个事件的句柄, 失败返回NULL。
BOOL WINAPI SetEvent(In HANDLE hEvent)
功能:将事件对象设置为有标记
参数:hEvent,事件对象的句柄
返回值:成功返回非0,失败返回0.
WaitForSingleObject函数在上一篇笔记已经解释,这里就不重复了。
上面的的事件对象使用的自动事件对象,如果想使用人工事件对象,可以将CreateEvent函数的第二个参数设置为true就可以。上面的事件对象是基本应用,其更多的用法可以去查询下PulseEvent这个函数,你会有更多发现。
相关文章推荐
- 单一控制器实现员工信息管理
- qt编译mysql驱动插件
- Android 自动注释,导入模板文件
- Linux 自学命令
- 产品新人应该学会的几点坚持
- 编写三各类Ticket、SealWindow、TicketSealCenter分别代表票信息、售票窗口、售票中心。售票中心分配一定数量的票,由若干个售票窗口进行出售,利用你所学的线程知识来模拟此售票过
- 树状数组详细分析
- Delphi_OD_代码_调试_Delphi反调试技术(以OD为例附核心原代码)
- 对比两个实体类属性值的差异
- 探索static——不需要能够使用该类实例?
- 直接插入排序
- AndroidManifest.xml
- tcpkill清除异常tcp连接
- Open vSwitch安装及配置
- keepalived+nginx反向代理访问后端web服务器
- C++的引用语法
- android TextView中文字通过SpannableString设置属性
- 关于对初学者ps合成工具使用的问答
- 有一个类为ClassA,有一个类为ClassB,在ClassB中有一个方法b,此方法抛出异常,在ClassA类中有一个方法a,请在这个方法中调用b,然后抛出异常。在客户端有一个类为TestC,有一个方
- iOS做透明引导页