事件内核对象
1. 手动重置事件:当一个手动重置事件被触发的时候,所有等待该事件的线程都变为可调度状态。所以要注意此时所有的线程都只能以只读的方式来访问内存,这也是多个线程能够同时运行的唯一原因
2. 自动重置事件:当一个自动重置事件被触发的时候,只有一个等待该事件的线程都变为可调度状态(当线程成功等到事件触发的时候,会自动的把事件重置为未触发状态),其余的继续等待。
创建一个事件内核对象
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset, //TRUE:手动重置事件; FALSE:自动重置事件
BOOL bInitialState, //TRUE:事件初始化为触发状态; FALSE:事件初始化为未触发状态
LPCSTR lpName
);
打开一个事件内核对象
其他进程中的线程要访问该事件对象可以调用OpenEvent
HANDLE OpenEvent(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCSTR lpName
);
改变事件触发状态
BOOL SetEvent(HANDLE hEvent); // 把事件变为触发状态
BOOL ResetEvent(HANDLE hEvent); // 把事件变为未触发状态
关闭事件对象
当不在需要事件对象时,要调用CloseHandle来将它关闭
BOOL CloseHandle(HANDLE hObject);
手动重置事件例子
#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;
int g_x = 0;
HANDLE g_hEvent;
// 线程只读
UINT WINAPI ThreadFunc1(PVOID pArguments)
{
WaitForSingleObject(g_hEvent, INFINITE);
cout << "ThreadFunc1.." << endl;
_endthreadex(0);
return 0;
}
// 线程只读
UINT WINAPI ThreadFunc2(PVOID pArguments)
{
WaitForSingleObject(g_hEvent, INFINITE);
cout << "ThreadFunc2.." << endl;
_endthreadex(0);
return 0;
}
// 线程只读
UINT WINAPI ThreadFunc3(PVOID pArguments)
{
WaitForSingleObject(g_hEvent, INFINITE);
cout << "ThreadFunc3.." << endl;
_endthreadex(0);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE handle[3];
unsigned unThreadID[3];
cout << "g_x initial value: " << g_x << endl;
// 创建一个未触发的手动重置事件
g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
handle[0] = (HANDLE)_beginthreadex(NULL,
0,
&ThreadFunc1,
NULL,
0,
&unThreadID[0]);
handle[1] = (HANDLE)_beginthreadex(NULL,
0,
&ThreadFunc2,
NULL,
0,
&unThreadID[1]);
handle[2] = (HANDLE)_beginthreadex(NULL,
0,
&ThreadFunc3,
NULL,
0,
&unThreadID[2]);
g_x = 100;
// 给g_x赋值后调用SetEvent触发事件,此时三个线程都变成可调度状态,获得CPU时间。
// 但是注意此时所有的三个线程都只能以只读的方式来访问内存,这也是三个线程能够同时运行的唯一原因
SetEvent(g_hEvent);
WaitForMultipleObjects(3, handle, TRUE, INFINITE);
CloseHandle(g_hEvent);
g_hEvent = NULL;
cout << "g_x Final value: " << g_x << endl;
getchar();
return 0;
}
自动重置事件例子
// ThreadDemo.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;
int g_x = 0;
HANDLE g_hEvent;
// 写入线程
UINT WINAPI ThreadFunc1(PVOID pArguments)
{
// 当线程成功等到事件对象触发的时候,自动重置事件会把事件对象重置为为触发状态,锁定资源,独占内存
WaitForSingleObject(g_hEvent, INFINITE);
int n = 0;
while (n < 5)
{
g_x += n;
n++;
cout << "ThreadFunc1.." << endl;
}
// 当线程结束,要释放资源,故把事件对象重置为触发状态,以便等待该资源的其他线程访问
SetEvent(g_hEvent);
_endthreadex(0);
return 0;
}
// 读线程
UINT WINAPI ThreadFunc2(PVOID pArguments)
{
WaitForSingleObject(g_hEvent, INFINITE);
cout << "ThreadFunc2.." << endl;
SetEvent(g_hEvent);
_endthreadex(0);
return 0;
}
// 写入线程
UINT WINAPI ThreadFunc3(PVOID pArguments)
{
WaitForSingleObject(g_hEvent, INFINITE);
int n = 0;
while (n < 5)
{
g_x += n;
n++;
cout << "ThreadFunc3.." << endl;
}
SetEvent(g_hEvent);
_endthreadex(0);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE handle[3];
unsigned unThreadID[3];
cout << "g_x initial value: " << g_x << endl;
// 创建一个未触发的自动动重置事件
g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
handle[0] = (HANDLE)_beginthreadex(NULL,
0,
&ThreadFunc1,
NULL,
0,
&unThreadID[0]);
handle[1] = (HANDLE)_beginthreadex(NULL,
0,
&ThreadFunc2,
NULL,
0,
&unThreadID[1]);
handle[2] = (HANDLE)_beginthreadex(NULL,
0,
&ThreadFunc3,
NULL,
0,
&unThreadID[2]);
g_x = 100;
// 由于事件初始化为未触发状态,所以在线程准备完毕后,调用SetEvent触发事件,此时只有一个线程都变成可调度状态,独占资源。其他线程继续等待
// 由于等待自动重置事件对象的线程是独占资源,故这些线程可读可写
SetEvent(g_hEvent);
WaitForMultipleObjects(3, handle, TRUE, INFINITE);
CloseHandle(g_hEvent);
g_hEvent = NULL;
cout << "g_x Final value: " << g_x << endl;
getchar();
return 0;
}