WaitForSingleObject函数

来源:互联网 发布:c语言函数库大全下载 编辑:程序博客网 时间:2024/05/04 19:12

 

WaitForSingleObject
当指定的对象处于有信号状态或者等待时间结束的状态时,此函数返回。
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);

参数:
hHandle:指定对象或事件的句柄;
dwMilliseconds: 等待时间,以毫妙为单位,当超过等待时间时,此函数将返回。如果该参数设置为0,则该函数立即返回,如果设置为INFINITE,则该函数直到有信号才返回。


hHandle可以是下列对象的句柄:

Change notification
Console input
Event
Job
Memory resource notification
Mutex
Process
Semaphore
Thread
Waitable timer

 

返回值:
如果此函数成功,该函数的返回之标识了引起该函数返回的事件。返回值如下:
   WAIT_ABANDONED(0x00000080L)
   指定的对象是一个互斥对象,该对象没有被拥有该对象的线程在线程结束前释放。互斥对象的所有权被同意授予调用该函数的线程。互斥对象被设置成为无信号状态。
   WAIT_OBJECT_0 (0x00000000L)
   指定的对象出有有信号状态。
   WAIT_TIMEOUT (0x00000102L)
   超过等待时间,指定的对象处于无信号状态
如果失败,返回 WAIT_FAILED;
备注:
此函数检查指定的对象或事件的状态,如果该对象处于无信号状态,则调用线程处于等待状态,此时该线程不消耗CPU时间,


WaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到WaitForSingleObject有返回直才执行后面的代码。在这里举个例子:

先创建一个全局Event对象g_event:

CEvent g_event;

在程序中可以通过调用CEvent::SetEvent设置事件为有信号状态。

下面是一个线程函数MyThreadPro()

UINT CFlushDlg::MyThreadProc( LPVOID pParam )
{
    WaitForSingleObject(g_event,INFINITE);
    For(;;)
       {
      ………….
       }
    return 0;
}

在这个线程函数中只有设置g_event为有信号状态时才执行下面的for循环,因为g_event是全局变量,所以我们可以在别的线程中通过g_event. SetEvent控制这个线程。

还有一种用法就是我们可以通过WaitForSingleObject函数来间隔的执行一个线程函数的函数体

UINT CFlushDlg::MyThreadProc( LPVOID pParam )
{
    while(WaitForSingleObject(g_event,MT_INTERVAL)!=WAIT_OBJECT_0)
    {
      ………………
    }
    return 0;
}
在这个线程函数中可以可以通过设置MT_INTERVAL来控制这个线程的函数体多久执行一次,当事件为无信号状态时函数体隔MT_INTERVAL执行一次,当设置事件为有信号状态时,线程就执行完毕了

 

函数在以下两种情况下返回:

1、指定的对象有信号;

2、超时;

如果使用了 INFINITE ,就表示不会超时,只有对象有信号才会返回

线程也有分为两中状态:有信号(signaled state)和无信号(nonsignaled state)。当线程还没结束期间该线程都处于nonsignaled state(哪怕是挂起了,阻塞了),当线程结束时,该线程就处于signaled state。

本质上还是有时间概念的,只是被MS给藏起来了。说到底就是个do while(true)循环.满足条件了就goto跳出。
WaitForSingleObject是kernel32.dll的导出函数,dasm下看到WaitForSingleObject又调用了ntdll.dll的NtWaitForSingleObject.
NtWaitForSingleObject又调用了KeWaitForSingleObject
以下是KeWaitForSingleObject的部分实现代码。(以上部分为原创,代码部分为转贴。)
do
{
WaitStatus = CurrentThread->WaitStatus;
CurrentThread->WaitBlockList = WaitBlock = &CurrentThread->WaitBlock[0];
CurrentObject = (PDISPATCHER_HEADER)Object;

if (KiIsObjectSignaled(CurrentObject, CurrentThread))
{
if (CurrentObject->SignalState != MINLONG)
{
KiSatisfyObjectWait(CurrentObject, CurrentThread);
Status = STATUS_WAIT_0;
goto WaitDone;

}
else
{
if (CurrentObject->Type == MutantObject)
{
KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
}
}
}

WaitBlock->Object = CurrentObject;
WaitBlock->Thread = CurrentThread;
WaitBlock->WaitKey = (USHORT)(STATUS_WAIT_0);
WaitBlock->WaitType = WaitAny;
WaitBlock->NextWaitBlock = NULL;

KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status);

CurrentThread->WaitStatus = Status;

if (Timeout != NULL)
{
//略.有超时设置的情况
}

InsertTailList(&CurrentObject->WaitListHead, &WaitBlock->WaitListEntry);

if (CurrentThread->Queue)
{
DPRINT("Waking Queue\n");
KiWakeQueue(CurrentThread->Queue);
}

PsBlockThread(&Status, Alertable, WaitMode, (UCHAR)WaitReason);

if (Status != STATUS_KERNEL_APC)
{
return Status;
}

DPRINT("Looping Again\n");
CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();

} while (TRUE);

WaitDone:

综合这些考虑。是有时间概念的。而这个do while究竟占用多少CPU资源就不好算了,但是肯定是一个有时间概念的东西。

原创粉丝点击