推荐参考博客:秒杀多线程第六篇 经典线程同步 事件Event
事件是内核对象,多用于线程间通信,可以跨进程同步
事件主要用到三个函数:CreateEvent,OpenEvent,SetEvent,ResetEvent 本文地址
CreateEvent
函数功能:创建事件
函数原型:
HANDLECreateEvent(
LPSECURITY_ATTRIBUTESlpEventAttributes,
BOOLbManualReset,
BOOLbInitialState,
LPCTSTRlpName
);
第一个参数:表示安全控制,一般直接传入NULL。
第二个参数:确定事件是手动置位还是自动置位,传入TRUE表示手动置位,传入FALSE表示自动置位。如果为自动置位,则对该事件调用WaitForSingleObject()后会自动调用ResetEvent()使事件变成未触发状态。打个小小比方,手动置位事件相当于教室门,教室门一旦打开(被触发),所以有人都可以进入直到老师去关上教室门(事件变成未触发)。自动置位事件就相当于医院里拍X光的房间门,门打开后只能进入一个人,这个人进去后会将门关上,其它人不能进入除非门重新被打开(事件重新被触发)。
第三个参数:表示事件的初始状态,传入TRUR表示已触发。
第四个参数:表示事件的名称,传入NULL表示匿名事件。
返回值:事件的句柄
OpenEvent
函数功能:根据名称获得一个事件句柄。
函数原型:
HANDLEOpenEvent(
DWORDdwDesiredAccess,
BOOLbInheritHandle,
LPCTSTRlpName //名称
);
函数说明:
第一个参数:表示访问权限,对事件一般传入EVENT_ALL_ACCESS。详细解释可以查看MSDN文档。
第二个参数:表示事件句柄继承性,一般传入TRUE即可。
第三个参数:表示名称,不同进程中的各线程可以通过名称来确保它们访问同一个事件。
返回值:返回事件的句柄
SetEvent
函数功能:触发事件
函数原型:BOOLSetEvent(HANDLEhEvent);
函数说明:每次触发后,必有一个或多个处于等待状态下的线程变成可调度状态。
ResetEvent
函数功能:将事件设为末触发
函数原型:BOOLResetEvent(HANDLEhEvent);
下面从一个例子说明:假设有三个线程都需要使用打印机,我们可以使用互斥量来控制,这样就可以保证每次只有一个线程在使用打印机
使用自动置位,那么在调用WaitForSingleObject()后会自动调用ResetEvent()使事件变为未触发状态,为了使后面的线程能够继续打印,需要在线程函数的结尾调用SetEvent来触发事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
#include<string> #include<iostream>
#include<process.h>
#include<windows.h>
using
namespace std;
//声明事件句柄
HANDLE
hev;
//线程绑定的函数返回值和参数是确定的,而且一定要__stdcall unsigned __stdcall threadFun( void
*param)
{ WaitForSingleObject(hev, INFINITE); //等待事件被触发
for ( int
i = 0; i < 10; i++)
cout<<*(string *)(param)<< " " ;
cout<<endl;
SetEvent(hev); //设置事件为触发状态,使后面的线程可以打印
return
1;
} int
main()
{ //创建一个未被触发的事件,事件是自动置位的
hev = CreateEvent(NULL, FALSE, FALSE, NULL);
SetEvent(hev); // 触发事件,使线程可以打印
HANDLE
hth1, hth2, hth3;
string s1 = "first" , s2 = "second" , s3 = "third" ;
//创建线程
hth1 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s1, 0, NULL);
hth2 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s2, 0, NULL);
hth3 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s3, 0, NULL);
//等待子线程结束
WaitForSingleObject(hth1, INFINITE);
WaitForSingleObject(hth2, INFINITE);
WaitForSingleObject(hth3, INFINITE);
//一定要记得关闭线程句柄
CloseHandle(hth1);
CloseHandle(hth2);
CloseHandle(hth3);
//千万别忘了删除事件
CloseHandle(hev);
} |
使用手动置位,调用WaitForSingleObject()后事件就一直是触发状态,线程可以任意的打印
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
#include<string> #include<iostream>
#include<process.h>
#include<windows.h>
using
namespace std;
//声明事件句柄
HANDLE
hev;
//线程绑定的函数返回值和参数是确定的,而且一定要__stdcall unsigned __stdcall threadFun( void
*param)
{ WaitForSingleObject(hev, INFINITE); //等待事件被触发
for ( int
i = 0; i < 10; i++)
cout<<*(string *)(param)<< " " ;
cout<<endl;
//SetEvent(hev);//设置事件为触发状态,使后面的线程可以打印
return
1;
} int
main()
{ //创建一个未被触发的事件,事件是手动置位的
hev = CreateEvent(NULL, TRUE, FALSE, NULL);
SetEvent(hev); // 触发事件,使线程可以打印
HANDLE
hth1, hth2, hth3;
string s1 = "first" , s2 = "second" , s3 = "third" ;
//创建线程
hth1 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s1, 0, NULL);
hth2 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s2, 0, NULL);
hth3 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s3, 0, NULL);
//等待子线程结束
WaitForSingleObject(hth1, INFINITE);
WaitForSingleObject(hth2, INFINITE);
WaitForSingleObject(hth3, INFINITE);
//一定要记得关闭线程句柄
CloseHandle(hth1);
CloseHandle(hth2);
CloseHandle(hth3);
//千万别忘了删除事件
CloseHandle(hev);
} |
【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3601458.html