基于同步对象的等待、唤醒机制:
一个线程可以等待一个对象或多个对象而进入等待状态(也叫睡眠状态),另一个线程可以触发那个等待对象,唤醒在那个对象上等待的所有线程。
一个线程可以等待一个对象或多个对象,而一个对象也可以同时被N个线程等待。这样,线程与等待对象之间是多对多的关系。他们之间的等待关系由一个队列和一个‘等待块’来控制,等待块就是线程与等待目标对象之间的纽带。
WaitForSingleObject可以等待那些“可等待对象”,哪些对象是‘可等待’的呢?进程、线程、作业、文件对象、IO完成端口、可等待定时器、互斥、事件、信号量等,这些都是‘可等待’对象,可用于WaitForSingleObject等函数。
‘可等待’对象又分为‘可直接等待对象’和‘可间接等待对象’
互斥、事件、信号量、进程、线程这些对象由于内部结构中的自第一个字段是DISPATCHER_HEADER结构(可以看成是继承了DISPATCHER_HEADER),因此是可直接等待的。而文件对象不带这个结构,但文件对象内部有一个事件对象,因此,文件对象是‘可间接等待对象’。
比如:信号量就是一种可直接等待对象,它的结构如下:
Struct KSEMAPHORE
{
DISPATCHER_HEADER Header;//公共头
LONG Limit;//最大信号量个数
}
Struct DISPATCHER_HEADER
{
…
LONG SignalState;//信号状态量(>0表示有信号,<=0表示无信号)
LIST_ENTRY WaitListHead;//等待块队列
…
}
WaitForSingleObject内部最终调用下面的系统服务
NTSTATUS
NtWaitForSingleObject(IN HANDLE ObjectHandle,//直接或间接可等待对象的句柄
IN BOOLEAN Alertable,//表示本次等待操作是否可被吵醒(即被强制唤醒)
IN PLARGE_INTEGER TimeOut OPTIONAL)//超时
{
PVOID Object, WaitableObject;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
LARGE_INTEGER SafeTimeOut;
NTSTATUS Status;
if ((TimeOut) && (PreviousMode != KernelMode))
{
_SEH2_TRY
{
SafeTimeOut = ProbeForReadLargeInteger(TimeOut);
TimeOut = &SafeTimeOut;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
Status = ObReferenceObjectByHandle(ObjectHandle,SYNCHRONIZE,NULL,PreviousMode,
&Object,NULL);
if (ESS(Status))
{
//得到那个对象的‘可直接等待对象’DefaultObject
WaitableObject = OBJECT_TO_OBJECT_HEADER(Object)->Type->DefaultObject;
if (IsPointerOffset(WaitableObject))//if DefaultObject是个偏移,不是指针
{
//加上偏移值,获得内部的‘可直接等待对象’
WaitableObject = (PVOID)((ULONG_PTR)Object + (ULONG_PTR)WaitableObject);
}
_SEH2_TRY
{
Status = KeWaitForSingleObject(WaitableObject,//这个函数只能等待‘直接等待对象’
UserRequest,PreviousMode,Alertable,TimeOut);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
ObDereferenceObject(Object);
}
return Status;
}
#de
windows源码分析(6)-线程同步篇 来自淘豆网m.daumloan.com转载请标明出处.