问题的引入:模仿12306多人同时抢票。
解决方法:使用事件对象。
事件对象
事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动o重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。
有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变成可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变成可调度线程。
创建事件对象
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, //被忽略的,必须为NULL
BOOL bManualReset, //TRUE表示手动重置状态,FALSE表示自动重置状态
BOOL bInitialState, //TRUE表示初始是有信号状态,FALSE表示无信号
LPTSTR lpName //事件对象的名称
);
设置事件对象的信号状态
BOOL SetEvent(
HANDLE hEvent
);
代码:
#include <Windows.h> //需要调用windows Api
#include <iostream>
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID lpParamter);
DWORD WINAPI Fun2Proc(LPVOID lpParamter);
HANDLE g_hEvent;
int nTickets = 100; //总票数
int main()
{
HANDLE hThred1, hThred2;
hThred1 = CreateThread(NULL, 0, Fun1Proc,
NULL, 0, NULL);
hThred2 = CreateThread(NULL, 0, Fun2Proc,
NULL, 0, NULL);
CloseHandle(hThred1);
CloseHandle(hThred2);
g_hEvent = CreateEvent(
NULL, //被忽略的,必须为NULL
FALSE, //TRUE表示手动重置状态,FALSE表示自动重置状态
FALSE, //TRUE表示初始是有信号状态,FALSE表示无信号
NULL); //事件对象的名称
SetEvent(g_hEvent); //
Sleep(4000);
CloseHandle(g_hEvent);
return 0;
}
DWORD WINAPI Fun1Proc(LPVOID lpParamter)
{
while (TRUE)
{
WaitForSingleObject(g_hEvent, INFINITE);
if (nTickets > 0)
{
Sleep(1);
cout << "thread1 sell ticket:" << nTickets-- << endl;
}
else
{
break;
}
/*
因为我们创建的是自动重置的事件对象,当线程1得到该事件对象后,
系统会自动将该事件对象设置为非信号状态。如果不调用SetEvent,
线程1、2后面都得不到该事件对象。
*/
SetEvent(g_hEvent); //设置为有信号状态
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID lpParamter)
{
while (TRUE)
{
WaitForSingleObject(g_hEvent, INFINITE);
if (nTickets > 0)
{
Sleep(1);
cout << "thread2 sell ticket:" << nTickets-- << endl;
}
else
{
break;
}
SetEvent(g_hEvent); //设置为有信号状态
}
return 0;
}