一、简介
互锁函数家族只能在单值上运行,根本无法使线程进入等待状态;关键代码段只适用于对单个进程中的线程实施同步;我们可以使用内核对象来实现线程同步。
二、等待函数
使用等待函数可以使线程进入等待状态,直到一个特定的内核对象变为已通知状。
(1)、等待单个事件
DWORD WaitForSingleObject(
HANDLE hObject, //该函数等待的对象句柄
DWORD dwMilliseconds); //等待超时时间
(2)、等待多个事件
DWORD WaitForMutipleObjects(
DWORD dwCount, //需要等待的内核数量
CONST HANDLE *phObjects, //内核对象句柄数组的指针
BOOL fWaitAll, //是否等待所有对象
DWORD dwMilliseconds); //等待超时时间
注:
当fWaitAll为TRUE时:线程进入等待状态,直到所有指定的内核对象都变为已通知状态。
当fWaitAll为FALSE时:线程进入等待状态,直到指定内核对象中的任何一个变为已通知状态。
(3)、等待函数返回值
WAIT_OBJECT_0: 所等待的对象变为已通知状态
WAIT_TIMEOUT: 等待超时
WAIT_FILED: 出现错误
三、事件内核对象
1、基本概念
事件内核对象是一基本内核对象,他能够通知一个操作已经完成,与其他内核对象一样,包含一个使用计数。该计数为BOOL型变量,用于指明该事件是否处于已通知状态还是未通知状态。另一计数用于指明该事件是自动重置事件还是人工重置事件。
2、事件的类型
(1)、自动重置事件
当自动重置事件得到通知时,等待该事件的线程只有一个变为可调度线程。
(2)、人工重置事件
当人工重置事情得到通知时,等待该事件的所有线程均变为可调度线程。
注:
当使用自动重置事件时,系统只允许一个辅助线程变成可调度状态,我们无法控制系统使哪个线程可调度,哪个线程等待。
当人工重置时由程序员来决定何时设置事件为已通知状态或未通知状态,当自动重置时,当等待的事件发生后,系统自动将事件置为相反的状态。无需程序员调用ResetEvent函数。
3、创建事件内核对象
HANDLE CreateEvent(
PSECURITY_ATTRIBUTES psa, //安全属性
BOOL fManualReset, //是否人工重置
BOOL fInitialState, //初始化未已通知还是未通知
PCTSTR pszName); //命名内核对象的名字
4、打开事件内核对象
HANDLE OpenEvent(
DWORD fdwAccess,
BOOL fInherit,
PCTSTR pszName);
5、设置事件对象未已通知状态
BOOL SetEvent(
HANDLE hEvent);
6、设置事件为未通知状态
BOOL ResetEvent(
HANDLE hEvent);
四、等待定时器内核对象
1、基本用途
等待定时器是再某个时间或按规定的间隔时间发出自己的信号通知的内核对象,通常用来再某个时间执行某个操作。
等待定时器对象总是再未通知状态创建,必须调用SetWaitableTimer函数来告诉定时器何时成为已通知状态。
2、创建等待定时器内核对象
HANDLE CreateWaitableTimer(
PSECURITY_ATTRIBUTES psa, //安全属性
BOOL fManualReset, //是人工重置还是自动重置
PCTSTR pszName); //命名内核对象的名称
3、打开等待定时器内核对象
HANDLE OpenWaitableTimer(
DWORD dwDesiredAccess, //访问属性
BOOL bInheritHandle, //可继承性
PCTSTR pszName); //命名内核对象的名称
4、设置等待定时器为已通知状态
BOOL SetWaitableTimer(
HANDLE hTimer, //要设置的定时器句柄
Const LARGE_INTEGER *pDueTime, //第一次报时的时刻
LONG lPeriod, //报时间隔
PTIMERAPCROUTINE pfnCompletionRoutine, //通常设为NULL
PVOID pvArgToCompletionRoutine, //通常设为NULL
BOOL fResume); //通常设为FALSE
5、撤销定时器
BOOL CancelWaitableTimer(
HANDLE hTimer); //需撤销的定时器的句柄
简单例子:
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;
HANDLE g_putApple;
HANDLE g_putBanana;
HANDLE g_eatApple;
HANDLE g_eatBanana;
HANDLE g_dish;
HANDLE m_hmtx;
/******************************************************************
*父亲放苹果,儿子吃苹果,母亲放香蕉,女儿吃香蕉
*在一个时间盘子之中只能放一样水果,苹果或香蕉
*****************************************************************/
//放苹果
UINT WINAPI PutAppleThread(PVOID pvParam)
{
for(int i = 0; i < 10; i++)
{
WaitForSingleObject(g_dish, INFINITE);
WaitForSingleObject(g_putApple, INFINITE);
cout << "put apple!/n";
SetEvent(g_eatApple);
Sleep(5);
}
return 0;
}
//放香蕉
UINT WINAPI PutBananaThread(PVOID pvParam)
{
for(int i = 0; i < 10; i++)
{
WaitForSingleObject(g_dish,INFINITE);
WaitForSingleObject(g_putBanana, INFINITE);
cout << "put banana!/n";
SetEvent(g_eatBanana);
}
return 0;
}
//吃苹果
UINT WINAPI EatAppleThread(PVOID pvParam)
{
for(int i = 0; i < 10; i++)
{
WaitForSingleObject(g_eatApple, INFINITE);
cout << "eat apple!/n";
SetEvent(g_putApple);
SetEvent(g_dish);;
}
return 0;
}
//吃香蕉
UINT WINAPI EatBananaThread(PVOID pvParam)
{
for(int i = 0; i < 10; i++)
{
WaitForSingleObject(g_eatBanana, INFINITE);
cout << "eat banana!/n";
SetEvent(g_putBanana);
SetEvent(g_dish);
Sleep(6);
}
return 0;
}
int main()
{
g_putApple = CreateEvent(NULL, FALSE, TRUE, NULL);
g_putBanana = CreateEvent(NULL, FALSE, TRUE, NULL);
g_eatApple = CreateEvent(NULL, FALSE, FALSE, NULL);
g_eatBanana = CreateEvent(NULL, FALSE, FALSE, NULL);
g_dish = CreateEvent(NULL, FALSE, TRUE, NULL);
m_hmtx = CreateMutex(NULL, FALSE, NULL);
HANDLE hThread[4];
int x;
hThread[0] = (HANDLE)_beginthreadex(NULL, 0, PutAppleThread, (void *)&x, 0, NULL);
hThread[1] = (HANDLE)_beginthreadex(NULL, 0, PutBananaThread, (void *)&x, 0, NULL);
hThread[2] = (HANDLE)_beginthreadex(NULL, 0, EatAppleThread, (void *)&x, 0, NULL);
hThread[3] = (HANDLE)_beginthreadex(NULL, 0, EatBananaThread, (void *)&x, 0, NULL);
char ch;
cin >> ch;
return 0;
}