转载自:http://www.cnblogs.com/yuanzfy/archive/2011/08/26/2154460.html
之前线程同步用互斥锁Mutex或用户模式的CriticalSection等来进行同步,而且使用效果一直很好,直到最近遇到新问题,朋友推荐用事件去处理。但是对事件了解比较少,所以摘了篇文章看,另外自己做了下试验(所以代码不是转的哦)。
概念:
事件是用来同步地位不相等的线程的,事件可以用来使一个线程完成一件事情,然后另外的线程完成剩下的事情。
事件的使用很灵活,自动事件的激发态是由人工来控制的(超级重要,尤其是在需要精确掌控是否处于有信号状态的时候),而Mutex在释放(releaseMetux)后就一直处于激发态,直到线程WaitForSingleObject。事件可以用来控制经典的读写模型和生产者和消费者模型。相应的方式为,生成者等待消费者的消费,再消费者消费完后通知生产者进行生产。
Mutex是排他的占有资源,一般用于地位相等的线程进行同步。每个线程都可以排他的访问一个资源或代码段,不存在哪个线程对资源访问存在优先次序。一个线程只能在Mutex处于激发态的时候访问被保护的资源或代码段,线程可以通过WaitForSingelObject来等待Mutex,在访问资源完成之后,ReleaseMutex释放Mutex,此时Mutex处于激发态。
注意:对句柄使用WaitForSIngleObject()之后的副作用(句柄状态的自动变化)
Mutex具有成功等待的副作用,在用WaitForSingleObject()等待到Mutex后,Mutex自动变为无信号状态,直到调用ReleaseMutex()使Mutex变为有信号状态为止;
自动事件也具有成功等待的副作用;
手动事件没有,必须调用ResetEvent()使手动事件变为未激发态;
进程和线程也没有成功等待的副作用。当线程或者进程函数返回时,线程内核对象变为激发态,但WaitForSingleObject并没有使线程或者进程的内核对象变为未激发态。
总之,事件一般用于控制线程的先后顺序,而Mutex一般用于排他的访问资源。
Event的使用:
首先创建事件:
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全属性
BOOL bManualReset, // 复位方式,1为手动复位,0为自动复位
BOOL bInitialState, // 初始状态,0为不可用状态即无信号,1为可用状态即有信号
LPCTSTR lpName // 对象名称
);
SetEvent()设置事件为有信号;ResetEvent()设置事件为无信号。
WaitForSingleObject()来等待Event变为有信号:
DWORD WaitForSignalObject(HANDLE hObject, DWORD dwMilliseconds);
返回值有以下几种:
WAIT_OBJECT_0 :表示等待对象已经变为有信号状态,如果设置为自动复位,还会把此信号再次变为无信号状态。
WAIT_TIMEOUT :表示等待超时
WAIT_FAILED :表示等待对象句柄是一个无效句柄。
代码示例:
功能:用主线程来等待子线程的执行结束
HANDLE hEvent;
int num=1;
DWORD WINAPI _threadProc(LPVOID lpParam)
{
for(int i=0; i<10000; i++)
{
for(int j=0; j<10000; j++)
;
}
num=10;
SetEvent(hEvent);
return 0;
}
void main()
{
//手动复位,初始时无信号
hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
if(hEvent==NULL)
{
printf("hEvent is null\n");
return;
}
HANDLE hThread=CreateThread(NULL, 0, _threadProc, NULL, 0, NULL);
DWORD dwRet=WaitForSingleObject(hEvent, INFINITE);
if(dwRet==WAIT_ABANDONED)
printf("WAIT_ABANDONED\n");
else if(dwRet==WAIT_TIMEOUT)
printf("WAIT_TIMEOUT\n");
else if(dwRet==WAIT_OBJECT_0)
printf("有信号状态\n");
else if(dwRet==WAIT_FAILED)
printf("WAIT_FAILED\n");
printf("sub thread run out, num is %d\n", num);
}