分类: C/C++
2014-08-05 20:20:06
Event是windows下可以使用的内核对象
我们知道如果只是为了让某个共享资源一次只让一个线程使用,则通过Critical Section与Mutex则可使资源使用达到互斥的目的.其中Critical Section是用户对象,Mutex是内核对象.除了此区别外,两者基本上差不多.
但是使用上面两种互斥方式时,虽然能保证一次只一个线程访问某个共享的资源,但是各个线程的执行顺序是没有保证的.另外除了用TerminateThread这种比较野蛮不推荐过多使用的方式外,没有更好的方式可以提前让一个线程结束.
但通过Event可以实现上面两各目的
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性
BOOL bManualReset, //使用手动还是自动
BOOL bInitialState, //初始状态
LPCTSTR lpName //event名字
);
其中第1,4个参数我们一般就设成NULL,如果涉及到不同进程间的线程同步问题时可能需要用到.
主要关注下第2,3个参数.
bManualReset设为TURE说明需要手动的去改变Event的状态,设为FALSE则是自动设置状态. bInitialState是初始状态,为TRUE时表示有信号,为FALSE时表示没信号.
只有有信号时线程才会运行.
举例说明下
HANDLE hEvent;
hEvent = CreateEvent(NULL, FALSE , FALSE,NULL); //表示自动设置状态,初始为FALSE;
AfxBeginThread(Fun,NULL);
UINT Fun(LPVOID pParam){
SetEvent(hEvent); //如果注释了它,则线程不会被调用,但如果bInitialState设为TRUE的话则省略它也行
WaitForSingleObject(hEvent,INFINITE)
//在这里会自动的执行ResetEvent(hEvent);又变成没信号,所以只有这一个线程会调用,其他线程不可用
cout<<"execute this code"<
//do something
//执行完了会自动执行SetEvent(hEvent); //又变成有信号.
}
由于bInitialState为FALSE,所以线程不能运行,必须通过SetEvent(hEVent)产生信号后才能运行.可以简单的理解成SetEvent(hEvent)就是和hInitialState设为TRUE达到的效果一样.
如果这样创建事件
上面讲的例子是自动,这里来讲下手动.
hEvent = CreateEvent(NULL, TRUE , FALSE,NULL);
UINT Fun(LPVOID pParam){
SetEvent(hEvent);
WaitForSingleObject(hEvent,INFINITE)
ResetEvent(hEvent);//在自动设置中不用显式写它,都是默认完成
cout<<"execute this code"<
//do something
SetEvent(hEvent); //在自动设置中也不用显式写它,都是默认完成
}
假如像一个线程执行完了才执行另外一个线程,咋整呢?
HANDLE hEventOne,hEventTwo;
hEventOne= CreateEvent(NULL, FALSE , FALSE,NULL);
hEventTwo= CreateEvent(NULL, FALSE , FALSE,NULL);
AfxBeginThread(FunOne,NULL);
AfxBeginThread(FunTwo,NULL);
UINT FunOne(LPVOID pParam){
SetEvent(hEventOne);
WaitForSingleObject(hEvent,INFINITE)
//do something...
SetEvent(hEventTwo) //使另一线程有信号
}
UINT FunTwo(LPVOID pParam){
WaitForSingleObject(hEventTwo,INFINITE)
//do something...
}
上面就保证只有FunOne执行完了,FunTwo才执行.
假如在其他地方让另外一个线程结束咋整呢,当然是除了用TerminateThread之外的方法.
HANDLE hEvent;
hEvent = CreateEvent(NULL, TRUE, FALSE,NULL); //一定得设为手动设置
SetEvent(hEvent);
AfxBeginThread(Fun,NULL);
UINT Fun(LPVOID pParam){
while(true){
if( !IsKilled() ){
cout<<"execute this code"<
//do something
}
}
}
BOOL IsKilled(){
if(WaitForSingleObject(hEvent,INFINITE) == WAIT_OBJECT_0)
return TRUE;
else
return FALSE;
}
void Stop(){
ResetEvent(hEvent); //这样就可以让前面的线程提前结束
}
当然自动设置的Event可以起到互斥的作用,同时只有一个线程使用某个资源,但上面变成手动的了就不用保证,所以你还可以跟Critical Section结合使用去实现这保证.
前面讲的都是WaitForSingleObject,讲的都是一次检查一个事件信号.而如果要检查多个事件信号要用WaitForMultipleObjects
DWORD WaitForMultipleObjects(
举例:
HANDLE hEvent1 = CreateEvent(NULL,TRUE,TRUE,NULL); //有信号
HANDLE hEvent2 = CreateEvent(NULL,TRUE,FALSE,NULL); //无信号
HANDLE hArrayHandle[2];
hArrayHandle[0] = hEvent1;
hArrayHandle[1] = hEvent2;
WaitForMultipleObjects(2, hArrayHandle, FALSE,INFINITE ); //只要有一个信号就行
WaitForMultipleObjects(2, hArrayHandle, TRUE,INFINITE ); // 必须所有的事件有信号
手动与自动
使线程按顺序执行
提前让线程结束
WaitForMultipleObjects
DWORD nCount, // 待检查事件句柄数量
CONST HANDLE *lpHandles, // 事件句柄数组
BOOL bWaitAll, // 如果是true,是所有的句柄有信号才返回,false是当有任何一个句柄有信号就返回
DWORD dwMilliseconds // 这个就是设置等待时间的
);