DWORD
WaitForSingleObject
(
HANDLE
hHandle,
// handle to object
DWORD
dwMilliseconds
// time-out interval毫秒,一般传入INFINITE(OXFFFFFFFF -1)
);
Value | Meaning |
---|---|
WAIT_FAILED | 传入无效参数,可调用GetLastError查看 |
WAIT_OBJECT_0 | 等待的对象被触发 |
WAIT_TIMEOUT | 时间耗尽 |
DWORD
WaitForMultipleObjects(//对多个对象操作
DWORD
nCount,
// number of handles in array 最大为
MAXIMUM_WAIT_OBJECTS
CONST
HANDLE
*lpHandles,
// object-handle array
BOOL
bWaitAll,
// wait option true所有都触发 false 一个触发就返回
DWORD
dwMilliseconds
// time-out interval);
HANDLE
h[3];
h[0]=hProcess1;
h[1=hProcess2;
h[2]=hProcess3;
DWORD
dw=WaitForMultipleOBjecs(3,h,
false
,5000);
switch
(dw)
{
case
WAIT_OBJEC_0:
//第一个对象被触发。
break
;
case
WAIT_OBJEC_0+1:
//第二个对象被触发。
break
;
case
WAIT_OBJEC_0+2:
//第三个对象被触发。
break
;
case
WAIT_TIMEOUT:
//超时
break
;
case
WAIT_FAILED:
//句柄无效。
break
;
}
使用 CreateEvent 创建一个事件内核对象。
HANDLE
CreateEvent(//还有个CreateEventEX函数
LPSECURITY_ATTRIBUTES lpEventAttributes,
// SD
BOOL
bManualReset,
// reset type true为手动重置 false自动重置
BOOL
bInitialState,
// initial state true 初始化为触发状态 false 初始化为未触发
LPCTSTR
lpName
// object name
);
BOOL
SetEvent(
HANDLE
hEvent
// handle to event); 把事件变为触发状态
BOOL
ResetEvent(
HANDLE
hEvent
// handle to event);把事件变为非触发状态
HANDLE
g_hEvent;
int
WINAPI _tWinMain(...)
{
g_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
//创建一个手动重置的对象并将这个事件对象放在一个全局变量中
DWORD
dwThreadID;
HANDLE
hThrasd[3];
hThrasd[0]=_beginthreadex(NULL,0,WordCount,NULL,0,&dwThreadID);
hThrasd[1]=_beginthreadex(NULL,0,SpellCheck,NULL,0,&dwThreadID);
hThrasd[1]=_beginthreadex(NULL,0,Gramer,NULL,0,&dwThreadID);
OpeFileAndReadIntoMemory();
SetEvent(g_hEvent);
...
}
DWORD
WINAPI WordCount(
PVOID
pvParam)
{
WaitForSingleObject(g_hEvent,INFINITE);
return
0;
}
DWORD
WINAPI SpellCheck(
PVOID
pvParam)
{
WaitForSingleObject(g_hEvent,INFINITE);
return
0;
}
DWORD
WINAPI Gramer(
PVOID
pvParam)
{
WaitForSingleObject(g_hEvent,INFINITE);
return
0;
}
HANDLE
CreateWaitableTimer( LPSECURITY_ATTRIBUTES lpTimerAttributes,
// SD
BOOL
bManualReset,
// reset type 同上,true手动重置;false 自动重置
LPCTSTR
lpTimerName
// object name);
BOOL
SetWaitableTimer(//用来触发
HANDLE
hTimer,
// handle to timer
const
LARGE_INTEGER *pDueTime,
// timer due time 什么时间触发,为负值时是相对时间
LONG
lPeriod,
// timer interval 多久触发一次 都是以毫秒为单位,为0时表示只触发一次
PTIMERAPCROUTINE pfnCompletionRoutine,
// completion routine
LPVOID
lpArgToCompletionRoutine,
// completion routine parameter
BOOL
fResume
// resume state);
HANDLE
hTimer;
SYSTEMTIME St; //表示本地时间
FILETIME ftLocal ,ftUTC;
LARGE_INTEGER liUTC;
hTimer=CreateWaitableTimer(NULL,
false
,NULL);
St.wyear=2013; //年
st.wMonth=1; //月
st.wDayOfWeek=0; //忽略
st.wDay=1; //日
st.wHour=1;
st.wMinute=1;
st.wSecond=0;
st.wMillisecons=0;//精确到毫秒
SystemTimeToFileTime(&st,&ftLocal);
//SYSTEMTIME结构转换为FILETIME结构。
LocalFileTimeToFileTime(&ftLocal,&ftUTC); //将本地时间转换为UTC(全球标准时间) time
liUTC.LowPart=ftUTC.dwlowDateTime;
liUTC.HighPart=ftUTC.dwHighDateTime;
SetWaitableTimer(hTimer,&liUTC,6*60*60*1000,NULL,NULL,
false
);
HANDLE
hTimer;
LARGE_INTEGER li;
hTimer=CreateWaitableTimer(NULL,
false
,NULL);
Li.quadpart=-(5*10000000); //设置为相对时间,第一次触发事假为调用结束的5秒后
SetWaitableTimer(hTimer,&li,6*60*60*1000,NULL,NULL,
false
);
HANDLE
CreateSemaphore(
PSECURITY_ATTRIBUTE psa,
//安全属性结构指针
LONG
lInitialCount,
//初始可用资源数
LONG
lMaximumCount,
//最大资源数
PCTSTR
pszName);
//信号量内核对象的名字
例:HANDLE
hSem = CreateSemaphore(NULL, 0, 5, NULL);
BOOL
ReleaseSemaphore(//
递增信号量的当前资源计数 等待函数会将资源数减一
HANDLE
hSemaphore,//信号量的句柄
LONG
lReleaseCount, //增加个数,必须大于0且不超过最大资源数量
LPLONG
lpPreviousCount //用来传出先前的资源计数,设为NULL表示不需要传出
);
#include <stdio.h>
#include <process.h>
#include <windows.h>
long
g_nNum;
unsigned
int
__stdcall Fun(
void
*pPM);
const
int
THREAD_NUM = 10;
//信号量与关键段
HANDLE
g_hThreadParameter;
CRITICAL_SECTION g_csThreadCode;
int
main()
{
printf
(
" 经典线程同步 信号量Semaphore\n"
);
//初始化信号量和关键段
g_hThreadParameter = CreateSemaphore(NULL, 0, 1, NULL);
//当前0个资源,最大允许1个同时访问
InitializeCriticalSection(&g_csThreadCode);
HANDLE
handle[THREAD_NUM];
g_nNum = 0;
int
i = 0;
while
(i < THREAD_NUM)
{
handle[i] = (
HANDLE
)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);
WaitForSingleObject(g_hThreadParameter, INFINITE);
//等待信号量>0
++i;
}
WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);
//删除信号量和关键段
DeleteCriticalSection(&g_csThreadCode);
CloseHandle(g_hThreadParameter);
for
(i = 0; i < THREAD_NUM; i++)
CloseHandle(handle[i]);
return
0;
}
unsigned
int
__stdcall Fun(
void
*pPM)
{
int
nThreadNum = *(
int
*)pPM;
ReleaseSemaphore(g_hThreadParameter, 1, NULL);
//信号量++
Sleep(50);
//some work should to do
EnterCriticalSection(&g_csThreadCode);
++g_nNum;
Sleep(0);
//some work should to do
printf
(
"ID = %d NUMS = %d\n"
, nThreadNum, g_nNum);
LeaveCriticalSection(&g_csThreadCode);
return
0;
}结果:
原子操作
)。互斥量对象包括一个使用计数、线程ID(标识占用这个互斥量的线程)以及一个递归计数(这个线程占用该互斥量的次数)。
互斥内核对象的行为特征和关键代码段有点类似,但是它是属于内核对象,而关键代码段是用户模式对象,这导致了互斥内核对象的运行速度比关键代码段要低。
所以,在考虑线程同步问题的时候,首先考虑用户模式的对象。但是,互斥内核对象可以跨进程使用,当需要实现多进程之间的线程同步,就可用考虑使用互斥内核对象。而这点,关键代码段无能为力。
互斥量的规则:创建一个互斥量:
HANDLE
CreateMutex(
PSECURITY_ATTRIBUTES psa,
BOOL
bInitialOwner,
//FALSE:ID和递归计数=0;TRUE:ID=调用线程ID,递归计数=1
PCTSTR
pszName);
OpenMutex来打开一个已存在的互斥量。
HANDLE
OpenMutex(
DWORD
dwDesiredAccess,
BOOL
bInheritHandle,
PCTSTR
pszName);
当目前占有互斥量的线程不再需要访问互斥资源时,它必须调用ReleaseMutex来释放互斥量。这是与其他内核对象不一样的地方
BOOL
ReleaseMutex(
HANDLE
hMutex);
特征 | 互斥量 | 关键段 |
---|---|---|
性能 | 慢 | 块 |
是否能跨进程使用 | 是 | 否 |
声明 | HANDLE hmtx; | CRITICAL_SECTION cs; |
初始化 | hmtx = CreateMutex (NULL, FALSE, NULL); | InitializeCriticalSection(&cs); |
清理 | CloseHandle(hmtx); | DeleteCriticalSection(&cs); |
无限等待 | WaitForSingleObject (hmtx, INFINITE); | EnterCriticalSection(&cs); |
0等待 | WaitForSingleObject (hmtx, 0); | TryEnterCriticalSection(&cs); |
任意时间长度的等待 | WaitForSingleObject (hmtx, dwMilliseconds); | 不支持 |
释放 | ReleaseMutex(hmtx); | LeaveCriticalSection(&cs); |
是否能同时等待其它 内核对象 | 是 (使用WaitForMultipleObjects 或类似函数) | 否 |
对象 | 何时处于未触发状态 | 何时处于触发状态 | 成功等待的副作用 |
进程 | 当进程仍在运行的时候 | 当进程终止运行时(ExitProcess, Te rminateProcess) | 无 |
线程 | 当线程仍在运行时 | 当线程终止运行时(ExitThread, TerminateThread) | 无 |
作业 | 当作业尚未超时的时候 | 当作业超时的时候 | 无 |
文件 | 当I / O请求正在处理时 | 当I / O请求处理完毕时 | 无 |
控制台输入 | 不存在任何输入 | 当存在输入时 | 无 |
文件修改通知 | 没有任何文件被修改 | 当文件系统发现修改时 | 重置通知 |
自动重置事件 | ResetEvent , PulseEvent或等待成功 | 当调用SetEvent / PulseEvent时 | 重置事件 |
手动重置事件 | ResetEvent或PulseEvent | 当调用SetEvent / PulseEvent时 | 无 |
自动重置等待计时器 | CancelWaitableTimer或等待成功 | 当时间到时(SetWaitableTimer) | 重置定时器 |
手动重置等待计时器 | CancelWaitableTimer | 当时间到时(SetWaitableTimer) | 无 |
信号量 | 等待成功 | 当数量> 0时(ReleaseSemaphore) | 数量递减1 |
互斥对象 | 等待成功 | 当未被线程拥有时(Release互斥对象) | 将所有权赋予线程 |
关键代码段(用户模式) | 等待成功((Try)EnterCriticalSection) | 当未被线程拥有时(LeaveCriticalSection) | 将所有权赋予线程 |
SRWLock (用户模式) | 等待成功的时候 (AcquireSRWLock(Exclusive)) | 不为线程占用的时候 (ReleaseSRWLock(Exclusive)) | 把所有权交给线程 |
条件变量 (用户模式) | 等待成功地时候 (SleepConditionVariable*) | 被唤醒的时候 (Wake(All)ConditionVariable) | 没有 |