16.1事件对象
事件对象也属于内核对象,主要包括三个成员:使用计数;指定是自动重置事件还是人工重置事件的布尔值;指定是已通知状态还是未通知状态的布尔值。
16.1.1创建事件对象
//CreateEvent函数创建一个匿名或者命名的事件对象:
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
// 若为NULL,指定默认的安全性
BOOL bManualReset, // TRUE为人工重置事件,否则自动重置事件
BOOL bInitialState, // TRUE有信号状态,否则是无信号状态
LPCTSTR lpName // 事件对象的名称
);
16.1.2设置事件对象的状态
//SetEvent函数将把指定的事件对象设置为有信号状态
BOOL SetEvent(
HANDLE hEvent // handle to event object
);
16.1.3重置事件对象的状态
//ResetEvent函数把指定的事件对象设置为无信号状态
BOOL ResetEvent(
HANDLE hEvent // handle to event object
);
16.1.4利用事件对象实现线程同步
#include<windows.h>
#include<iostream.h>
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
HANDLE g_hEvent=100;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
//创建互斥对象
g_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
//创建线程
hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL);
hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(4000);//让主线程睡四秒,系统给线程1和线程2分配时间片运行
//关闭事件对象句柄
CloseHandle(g_hEvent);
}
//线程1的入口函数
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket:"<<tickets--<<endl;
}
else
{
break;
}
}
return 0;
}
//线程2的入口函数
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
if(tickets>0)
{
Sleep(1);
cout<<"thread2 sell ticket:"<<tickets--<<endl;
}
else
{
break;
}
}
return 0;
}
//运行程序,发现并没有完成车票销售,原因就是创建事件对象时,第三个参数是FALSE表示无信号状态。解决方法一就是将第三个参数设置为TRUE;解决方法二就是在创建事件对象之后,加上SetEvent(g_hEvent);再次运行程序会打印0号车票。
//其实为了实现线程间的同步,不应该使用人工重置的事件对象,而应该使用自动重置的事件对象,因此可以不用手动调用ResetEvent函数,因此解决方法如下:
#include<windows.h>
#include<iostream.h>
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
HANDLE g_hEvent;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
//创建互斥对象
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
SetEvent(g_hEvent);
//创建线程
hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL);
hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(4000);//让主线程睡四秒,系统给线程1和线程2分配时间片运行
//关闭事件对象句柄
CloseHandle(g_hEvent);
}
//线程1的入口函数
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket:"<<tickets--<<endl;
SetEvent(g_hEvent);
}
else
{
SetEvent(g_hEvent);
break;
}
}
return 0;
}
//线程2的入口函数
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
if(tickets>0)
{
Sleep(1);
cout<<"thread2 sell ticket:"<<tickets--<<endl;
SetEvent(g_hEvent);
}
else
{
SetEvent(g_hEvent);
break;
}
}
return 0;
}
//运行结果如图。
16.1.5保证应用程序只有一个实例运行
//利用CreateEvent函数创建命名对象并根据返回值判断应用程序是否已经有一个实例在运行。如果有程序退出。
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
if(g_hEvent)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run!"<<endl;
return;
}
SetEvent(g_hEvent);
}