多线程Event

来源:互联网 发布:电脑上翻墙用什么软件 编辑:程序博客网 时间:2024/05/19 15:42

我们知道如果只是为了让某个共享资源一次只让一个线程使用,则通过Critical Section与Mutex则可使资源使用达到互斥的目的.其中Critical Section是用户对象,Mutex是内核对象.除了此区别外,两者基本上差不多.

但是使用上面两种互斥方式时,虽然能保证一次只一个线程访问某个共享的资源,但是各个线程的执行顺序是没有保证的.另外除了用TerminateThread这种比较野蛮不推荐过多使用的方式外,没有更好的方式可以提前让一个线程结束.

但通过Event可以实现上面两各目的

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"<<endl;

     //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"<<endl;

//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"<<endl;

//do something

}

}

}

 

BOOL IsKilled(){

 if(WaitForSingleObject(hEvent,INFINITE) == WAIT_OBJECT_0)

   return TRUE;

else

 return FALSE;

}

 

void Stop(){

 ResetEvent(hEvent); //这样就可以让前面的线程提前结束

}

 

当然自动设置的Event可以起到互斥的作用,同时只有一个线程使用某个资源,但上面变成手动的了就不用保证,所以你还可以跟Critical Section结合使用去实现这保证.

 

 

WaitForMultipleObjects

前面讲的都是WaitForSingleObject,讲的都是一次检查一个事件信号.而如果要检查多个事件信号要用WaitForMultipleObjects

 

DWORD WaitForMultipleObjects(
DWORD nCount, // 待检查事件句柄数量
CONST HANDLE *lpHandles, // 事件句柄数组
BOOL bWaitAll, // 如果是true,是所有的句柄有信号才返回,false是当有任何一个句柄有信号就返回
DWORD dwMilliseconds // 这个就是设置等待时间的
);

举例:

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 ); // 必须所有的事件有信号

 

原创粉丝点击