多线程与事件对象

 

http://hi.baidu.com/netspider_2007/blog/item/c164f63eb6cbd4ca7c1e7130.html

创建或打开一个命名的或无名的事件对象
  函数原型:
  HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全属性
  BOOL bManualReset, // 复位方式
  BOOL bInitialState, // 初始状态
  LPCTSTR lpName // 对象名称
  );
  参数:
  lpEventAttributes:
  [输入]一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承。如果lpEventAttributes是NULL,此句柄不能被继承。
  Windows NT/2000:lpEventAttributes的结构中的成员为新的事件指定了一个安全符。如果lpEventAttributes是NULL,事件将获得一个默认的安全符。
  bManualReset:
  [输入]指定将事件对象创建成手动复原还是自动复原。如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。如果设置为FALSE,当事件被一个等待线程释放以后,系统将会自动将事件状态复原为无信号状态。
  bInitialState:
  [输入]指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。
  lpName:
  [输入]指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。

还是上文 多线程与互斥对象 用售票系统为例,介绍事件对象

#include <windows.h>
#include <iostream.h>

DWORD WINAPI Fun1Proc(
LPVOID lpParameter   // thread data
);

DWORD WINAPI Fun2Proc(
LPVOID lpParameter   // thread data
);

int tickets=100;
HANDLE g_hEvent;

void main()
{
HANDLE hThread1;
HANDLE hThread2;
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);

g_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);//手动的、无信号状态
Sleep(4000);

}

DWORD WINAPI Fun1Proc(
LPVOID lpParameter   // thread data
)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
   if(tickets>0)
   {
    Sleep(1);
    cout<<"thread1 sell ticket : "<<tickets--<<endl;
   }
   else
    break;
   SetEvent(g_hEvent);
}

return 0;
}

DWORD WINAPI Fun2Proc(
LPVOID lpParameter   // thread data
)
{

while(TRUE)
{
  WaitForSingleObject(g_hEvent,INFINITE);
   if(tickets>0)
   {
    Sleep(1);
    cout<<"thread2 sell ticket : "<<tickets--<<endl;
   }
   else
    break;
   SetEvent(g_hEvent);
}

return 0;
}

上面代码执行,没有任何结果,分析原因:
g_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);//手动的、无信号状态
参数二:bManualReset=TRUE,必须用ResetEvent函数来手工将事件的状态复原到无信号状态
参数三 bInitialState=FALSE 限定改信号在main函数中处于无信号状态;
msdn中 实际要使用setEvent(g_hEvent);

(2)setEvent
setEvent:设置事件的状态为有标记(bInitialState),释放任意等待线程。如果事件是手工的,此事件将保持有标记直到调用ResetEvent。
这种情况下将释放多个线程,如果事件是自动的,此事件将保持有标记,直到一个线程被释放,系统将设置事件的状态为无标记。
如果没有线程在等待,则此事件将保持有标记,直到一个线程被释放。
在上面代码中增加:
g_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
setEvent(g_hEvent);

程序运行 但是打印出tickets=0情况,这样肯定不正确,这是为什么呢?

当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。
当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。

g_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);//是人工的
所以两个线程同时执行了,导致了为0情况,所以同步失败了;

(3)ResetEvent
Sets the specified event object to the nonsignaled state.这个针对,手动的而言,需要当调用时候,需要设置为无信号状态:修改线程函数:
DWORD WINAPI Fun1Proc(
LPVOID lpParameter   // thread data
)
{
while(TRUE)
{
   WaitForSingleObject(g_hEvent,INFINITE);
ResetEvent(g_hEvent);
   if(tickets>0)
   {
    Sleep(1);
    cout<<"thread1 sell ticket : "<<tickets--<<endl;
   }
   else
    break;
  SetEvent(g_hEvent);
}

return 0;
}

但是还是没有成功 还是有0出现


(4)对于线程之间同步 不要使用人工重置的对象
使用自动重置的对象,
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);//是自动
int main()
{
HANDLE thread1,thread2;
thread1=CreateThread(NULL,0,Fun1Thread,NULL,0,NULL);
thread2=CreateThread(NULL,0,Fun2Thread,NULL,0,NULL);
CloseHandle(thread1);
    CloseHandle(thread2);
  
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);//自动、无信号
SetEvent(g_hEvent);
  
   Sleep(4000);
    CloseHandle(g_hEvent);
return 0;
}

DWORD WINAPI Fun1Thread( LPVOID lpParameter)
{
    while(true)
{
   WaitForSingleObject(g_hEvent,INFINITE);//signaled state 直到有信号状态,有返回值时候 才执行下面代码

   if(tickets>0)
   {
     Sleep(3);
   printf("thread1 tickets=%d\n",tickets--);
   }
   else
    break;
}
return 0;
}
DWORD WINAPI Fun2Thread( LPVOID lpParameter)
{
    while(true)
{
   WaitForSingleObject(g_hEvent,INFINITE);
   if(tickets>0)
   {
     Sleep(2);
   printf("thread2 tickets=%d\n",tickets--);
   }
   else
    break;
}
return 0;
}


结果:打印,tickets=100,其它都没有反应;


当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
线程一中 WaitForSingleObject(g_hEvent,INFINITE);设置为非信号状态;(操作系统分配),这样导致了另外一个线程将不能调度,所以导致上面执行一次;

所以修改一下,让下一个获得请求; 修改如下:
DWORD WINAPI Fun1Proc(
LPVOID lpParameter   // thread data
)
{
while(TRUE)
{
   WaitForSingleObject(g_hEvent,INFINITE);
   if(tickets>0)
   {
    Sleep(1);
    cout<<"thread1 sell ticket : "<<tickets--<<endl;
   }
   else
    break;
SetEvent(g_hEvent);//对于自动的设置为有信号状态
}

return 0;

你可能感兴趣的:(多线程与事件对象)