Win 32 多线程程序设计学习笔记之三:*WaitFor*Object函数

1.等待一个线程的结束

DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);

参数
hHandle: 等待对象的 handle(代表一个核心对象)。在本例中,此为线程 handle。
dwMilliseconds :等待的最长时间。时间终了,即使 handle 尚未成为激发状态,此函数还是要返回。此值可以是 0
                   (代表立刻返回),也可以是 INFINITE 代表无穷等待。

返回值

如果函数失败,则传回WAIT_FAILED。这时候你可调用 GetLastError() 取得更多信息。此函数的成功有三个因素:
1. 等待的目标(核心对象)变成激发状态。这种情况下返回值将为WAIT_OBJECT_0。
2. 核心对象变成激发状态之前,等待时间终了。这种情况下返回值将为WAIT_TIMEOUT。
3. 如果一个拥有 mutex(互斥器)的线程结束前没有释放 mutex,则传回 WAIT_ABANDONED。


        关于 time-out,有一个特别重要的用途,但很少被人注意。设定 time-out为 0,使你能够检查 handle 的状态并立刻返回,没有片刻停留。如果 handle已经备妥,那么这个函数会成功并传回 WAIT_OBJECT_0。否则,这个函数立刻返回并传回 WAIT_TIMEOUT。

        

        WaitForSingleObject() 可以面对许多种 handles 工作,不一定要是本例所使用的线程 handle。事实上,Win32 中大部分以 HANDLE 表示的对象都能够作为 WaitForSingleObject() 的等待目标。视你所拥有的对象不同,操作系统等待的事情也不一样。形式上来说,系统等待着这一对象“被激发”。


        可被 WaitForSingleObject() 使用的核心对象有两种状态:激发与未激发。WaitForSingleObject() 会在目标物变成激发状态时返回。事实上我们也几乎是以此作为对象激发与否的操作型定义。

        当核心对象被激发时,会导致WaitForSingleObject() 醒来。稍后你将看到的其他 Wait() 函数也是如此。

        当线程正在执行时,线程对象处于未激发状态。当线程结束时,线程对象就被激发了。因此,任何线程如果等待的是一个线程对象,将会在等待对象结束时被调用,因为当时线程对象自动变成激发状态。

        数个线程可以同时等待相同的线程 handle。当该线程 handle 变成激发状态时,所有等待中的线程都会被唤醒。然而,其他核心对象可能只唤醒一个等待中的线程。到底是哪一种行为,得视你等待什么样的对象而定。某些对象的激发状态只能够维持到一个等待中的线程被唤醒,其他对象的激发状态则或许可以维持到它又被明白地重置(reset)。


2.核心对象激发状态的意义

  1. Thread*(线程) 当线程结束时,线程对象即被激发。当线程还在进行时, 则对象处于未激发状态。线程对象系由CreateThread() 或 CreateRemoteThread() 产生
  2. Process*(进程) 当进程结束时,进程对象即被激发。当进程还在进行时, 则对象处于未激发状态。CreateProcess() 或OpenProcess() 会传回一个进程对象的 handle
  3. Change Notification 当一个特定的磁盘子目录中发生一件特别的变化时,此对象即被激发。此对象系由 FindFirstChangeNotification()
  4. Console Input* 当 console 窗口的输入缓冲区中有数据可用时,此对象将处于激发状态。CreateFile() 和 GetStdFile() 两函数可以获得 console handle。
  5. Event* Event 对象的状态直接受控于应用程序所使用的三个Win32 函数:SetEvent()、PulseEvent()、ResetEvent()。CreateEvent() 和 OpenEvent() 都可以传回一个 event object handle。Event 对象的状态也可以被操作系统设定——如果使用于“overlapped”操作时
  6. Mutex* 如果 mutex 没有被任何线程拥有,它就是处于激发状态。一旦一个等待 mutex 的函数返回了,mutex 也就自动重置为未激发状态。CreateMutex() 和 OpenMutex()都可以获得一个 mutex handle。
  7. Semaphore* Semaphore 有点像 mutex,但它有个计数器,可以约束其拥有者(线程)的个数。当计数器内容大于0 时,semaphore 处于激发状态,当计数器内容等于0 时,semaphore 处于未激发状态。CreateSemaphore() 和OpenSemaphore() 可以传回一个 semaphore handl
3.等待多个对象
DWORD WaitForMultipleObjects(
DWORD nCount,
CONST HANDLE *lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds
);
参数
nCount 表示 lpHandles 所指之 handles 数组的元素个数。最大容量是 MAXIMUM_WAIT_OBJECTS。
lpHandles 指向一个由对象 handles 所组成的数组。这些
handles 不需要为相同的类型。
bWaitAll 如果此为 TRUE,表示所有的 handles 都必须激发,此函数才得以返回。否则此函数将在任何一个
handle 激发时就返回。
dwMilliseconds 当该时间长度终了时,即使没有任何 handles 激发,此函数也会返回。此值可为 0,以便测试。亦
可指定为 INFINITE,表示无穷等待。

返回值
WaitForMultipleObjects() 的返回值有些复杂。
i 如果因时间终了而返回, 则返回值是 WAIT_TIMEOUT , 类似WaitForSingleObject()。
i 如果 bWaitAll 是 TRUE,那么返回值将是 WAIT_OBJECT_0。
i 如果 bWaitAll 是 FALSE,那么将返回值减去 WAIT_OBJECT_0,就表示数组中的哪一个 handle 被激发了。
i 如果你等待的对象中有任何 mutexes , 那么返回值可能从WAIT_ABANDONED_0 到 WAIT_ABANDONED_0 + nCount - 1。
i 如果函数失败, 它会传回 WAIT_FAILED。这时候你可以使用GetLastError() 找出失败的原因。

        注 意 , handles 数组中的元素个数有上限, 绝对不能够超过MAXIMUM_WAIT_OBJECTS。在 Windows NT 3.x 和 4.0 中,其值为 64

4.在一个 GUI 程序中等待
        “主消息循环”是 16 位Windows 程序中得以不依靠 busy loop 而能够等待某些事物的一个地方。Windows 程序中的标准消息循环看起来像这个样子:
while (GetMessage(&msg, NULL, 0, 0,))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
        GetMessage() 有点像是特殊版本的 WaitForSingleObject(),它等待消息而不是核心对象。一旦你调用 GetMessage(),除非有一个消息真正进入你的消息队列(message queue)之中,否则它不会返回。在此期间,Windows 就可以
自由地将 CPU 时间给予其他程序。GetMessage() 是 Win16 合作型多任务的关键。
        “常常回到主消息循环”是十分重要的一件事。如果你没这么做,你的窗口就会停止重绘,你的程序菜单就不再有作用,用户不喜欢的事情则慢慢开始发生。问题是,如果你正使用 WaitForSingleObject()或WaitForMultipleObjects()等待某个对象被激发,你根本没有办法回到主消息循环中去。
        为了解决这个问题,主消息循环必须修改,使它得以同时等待消息或是核心对象被激发。你必须使用一个 MsgWaitForMultipleObjects() 函数。这个函数非常类似 WaitForMultipleObjects(),但它会在“对象被激发”或“消息到达队列”时被唤醒而返回。MsgWaitForMultipleObjects() 多接受一个参数,允许指定哪些消息是观察对象。
DWORD MsgWaitForMultipleObjects(
DWORD nCount,
LPHANDLE pHandles,
BOOL fWaitAll,
DWORD dwMilliseconds,
DWORD dwWakeMask
);
参数
dwWakeMask 欲观察的用户输入消息,可以是:
QS_ALLINPUT
QS_HOTKEY
QS_INPUT
QS_KEY
QS_MOUSE
QS_MOUSEBUTTON
QS_MOUSEMOVE
QS_PAINT
QS_POSTMESSAGE
QS_SENDMESSAGE
QS_TIMER
返回值
和 WaitForMultipleObjects() 相比较,MsgWaitForMultipleObjects() 有一些额外的返回值意义。为了表示“ 消息到达队列” , 返回值将是WAIT_OBJECT_0 + nCount。
        MsgWaitForMultipleObjects() 的正确使用方式是改写主消息循环,使得激发状态之 handles 得以像消息一样地被对待。视其返回值而定,消息循环或许调用 GetMessage() 并处理下一个消息,或许调用你所提供的一个处理函数,以处理受激发的handles。

你可能感兴趣的:(Win 32 多线程程序设计学习笔记之三:*WaitFor*Object函数)