1. 事件
创建事件函数CreateEvent
HANDLE WINAPI CreateEvent(
__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,//SD
__in BOOL bManualReset, //是否手动重新设置标志位,如果为TRUE,即用来互斥,如果为FALSE,即用来通知
__in BOOL bInitialState,//刚开始是否是有信号
__in_opt LPCTSTR lpName //名字
);
事件与互斥体的最大的区别就是,他可以用来通知,可以通过下面的线程同步的例子来感受事件与互斥体的不同
2. 线程同步
<1>线程互斥:线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。
<2>线程同步:线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
同步=互斥+有序
线程同步 最经典的是 生产者与消费者模型,下面就用互斥内核对象和事件分别来实现生产者和消费者模型,借此来感受事件和互斥对象的不同之处
用互斥内核对象实现线程同步
#include "stdafx.h"
#include <windows.h>
HANDLE hMutex;
int g_Count;
DWORD WINAPI ThreadProduct(LPVOID lParam)
{
int i;
for(i=0; i<100; i++)
{
WaitForSingleObject(hMutex, INFINITE);
if(g_Count == 0)
{
g_Count = 1;
printf("Procuct %d------------------\n", g_Count);
}
else
{
i--;
}
ReleaseMutex(hMutex);
}
return 0;
}
DWORD WINAPI ThreadConsume(LPVOID lParam)
{
int i;
for(i=0; i<100; i++)
{
WaitForSingleObject(hMutex, INFINITE);
if(g_Count == 1)
{
g_Count = 0;
printf("Consume %d\n", g_Count);
}
else
{
i--;
}
ReleaseMutex(hMutex);
}
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hThread[2] = {0};
hMutex = CreateMutex(NULL,FALSE, NULL);
hThread[0] = CreateThread(NULL,0, ThreadProduct, NULL,0,NULL);
hThread[1] = CreateThread(NULL,0, ThreadConsume, NULL,0,NULL);
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
CloseHandle(hMutex);
return 0;
}
这样做看似没有任何问题,但是却十分消耗CPU时间片,将代码稍作修改,在else里面都加入 printf("++++++++++++++++++++++++\n");表示浪费的CPU时间,运行程序,打印结果为:
可见这样做,CPU浪费是多么严重,那么怎么完美的实现生产者和消费者呢????
这个时候就需要用到事件了,我们可以这样写代码
用事件来实现线程同步
#include "stdafx.h"
#include <windows.h>
HANDLE hSetEvent, hConEvent;
int g_Count;
DWORD WINAPI ThreadProduct(LPVOID lParam)
{
int i;
for(i=0; i<100; i++)
{
WaitForSingleObject(hSetEvent, INFINITE);
g_Count = 1;
printf("Procuct %d------------------\n", g_Count);
SetEvent(hConEvent); //这里可以理解为将本线程挂起,立马去执行另一个线程,不存在浪费时间片的现象,这就是“通知”
}
return 0;
}
DWORD WINAPI ThreadConsume(LPVOID lParam)
{
int i;
for(i=0; i<100; i++)
{
WaitForSingleObject(hConEvent, INFINITE);
g_Count = 0;
printf("Consume %d\n", g_Count);
SetEvent(hSetEvent);//这里可以理解为将本线程挂起,立马去执行另一个线程,不存在浪费时间片的现象,这就是“通知”
}
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hThread[2] = {0};
hSetEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
hConEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
hThread[0] = CreateThread(NULL,0, ThreadProduct, NULL,0,NULL);
hThread[1] = CreateThread(NULL,0, ThreadConsume, NULL,0,NULL);
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
CloseHandle(hSetEvent);
CloseHandle(hConEvent);
return 0;
}
运行结果为:
所以事件与互斥对象最大的不同就是,在创建的时候,CreateEvent的第二个参数设置为FALSE的时候可以理解为“通知”,当设置为TRUE的时候,就是互斥,就与互斥对象实现的功能一样了