Wait 函数

Wait 函数 允许线程阻止其自身执行。 直到满足指定的条件,才会返回 wait 函数。 Wait 函数的类型决定了使用的一组条件。 调用 wait 函数时,它会检查是否满足了等待条件。 如果尚未满足条件,则调用线程将进入等待状态,直到满足等待条件的条件或指定的超时间隔。

单对象等待函数

SignalObjectAndWaitWaitForSingleObjectWaitForSingleObjectEx函数需要一个同步对象的句柄。 当发生以下情况之一时,这些函数将返回:

  • 指定的对象处于终止状态。
  • 超时间隔已过去。 超时间隔可以设置为 " 无限 ",以指定等待时间不会超时。

SignalObjectAndWait函数可让调用线程以原子方式将对象的状态设置为 "已终止",并等待另一个对象的状态设置为 "已终止"。

多对象等待函数

WaitForMultipleObjectsWaitForMultipleObjectsExMsgWaitForMultipleObjectsMsgWaitForMultipleObjectsEx函数使调用线程可以指定包含一个或多个同步对象句柄的数组。 当发生以下情况之一时,这些函数将返回:

  • 指定对象之一的状态设置为 "已终止",或者所有对象的状态均设置为 "已终止"。 控制是否将在函数调用中使用一种或多种状态。
  • 超时间隔已过去。 超时间隔可以设置为 " 无限 ",以指定等待时间不会超时。

MsgWaitForMultipleObjectsMsgWaitForMultipleObjectsEx函数允许指定对象句柄数组中的输入事件对象。 在线程的输入队列中指定要等待的输入类型时,可以执行此操作。 例如,线程可以使用 MsgWaitForMultipleObjects 来阻止其执行,直到指定对象的状态设置为 "已终止",并在线程的输入队列中有可用的鼠标输入。 线程可以使用 GetMessagePeekMessageAPeekMessageW 函数检索输入。

等待所有对象的状态设置为 "已终止" 时,这些多对象函数不会修改指定对象的状态,直到已将所有对象的状态设置为 "已终止"。 例如,互斥体对象的状态可以发出信号,但在数组中指定的其他对象的状态也设置为 "已终止" 之前,调用线程不会获得所有权。 同时,一些其他线程可能会获得 mutex 对象的所有权,从而将其状态设置为非终止。

在等待将单个对象的状态设置为 "已终止" 时,这些多对象函数将按从索引0开始的顺序检查数组中的句柄,直到其中一个对象处于终止状态。 如果多个对象变为已发出信号,则函数将返回数组中其对象被终止的第一个句柄的索引。

可报警 Wait 函数

MsgWaitForMultipleObjectsExSignalObjectAndWaitWaitForMultipleObjectsExWaitForSingleObjectEx函数与其他等待函数的不同之处在于,它们可以选择执行 可报警等待操作。 在可报警等待操作中,如果满足指定的条件,该函数可能会返回,但如果系统将 i/o 完成例程或 APC 排队等待线程执行,则该函数也可以返回。 有关可报警等待操作和 i/o 完成例程的详细信息,请参阅 同步和重叠的输入和输出。 有关 Apc 的详细信息,请参阅 异步过程调用

注册的 Wait 函数

RegisterWaitForSingleObject函数不同于其他等待函数,因为等待操作由线程 池中的线程执行。 如果满足指定的条件,则回调函数将由线程池中的工作线程执行。

默认情况下,已注册的等待操作为多等待操作。 每次向事件发出信号时,系统都会重置计时器 (或超时间隔已) ,直到调用 unregisterwaitex 期间 函数来取消操作。 若要指定等待操作只应执行一次,请将 RegisterWaitForSingleObjectdwFlags 参数设置为 WT _ EXECUTEONLYONCE

如果该线程调用使用 Apc 的函数,请将 RegisterWaitForSingleObjectdwFlags 参数设置为 WT _ EXECUTEINPERSISTENTTHREAD

等待地址

线程可以使用 WaitOnAddress 函数等待目标地址的值从某个不需要的值更改为其他任何值。 这使线程可以等待更改值,而无需旋转或处理线程捕获不需要的值时,但在线程可以等待之前值发生更改的同步问题。

当修改目标值的代码通过调用 WakeByAddressSingle来唤醒单个等待线程或 WakeByAddressAll唤醒所有等待线程时, WaitOnAddress返回。 如果使用 WaitOnAddress 指定了超时间隔,并且没有线程调用唤醒函数,则该函数将在超时间隔结束时返回。 如果未指定超时间隔,则线程会无限期等待。

等待函数和超时间隔

指定的超时间隔的准确性取决于系统时钟的分辨率。 固定速率的系统时钟 "刻度"。 如果超时间隔小于系统时钟的分辨率,则等待时间可能会小于指定的时间长度。 如果超时间隔大于一个刻度,但小于两个,则等待时间可能介于1到2个刻度之间,依此类推。

若要提高等待函数的超时间隔的准确性,请调用 timeGetDevCaps 函数以确定支持的最小计时器分辨率和 timeBeginPeriod 函数,以将计时器分辨率设置为最小值。 调用 timeBeginPeriod 时请小心,因为频繁调用会显著影响系统时钟、系统电源使用情况和计划程序。 如果调用 timeBeginPeriod,请在应用程序的早期调用一次,并确保在应用程序的最末尾调用 timeEndPeriod 函数。

等待函数和同步对象

等待函数可以修改某些类型的 同步对象的状态。 仅对其终止状态导致函数返回的对象或对象进行修改。 Wait 函数可以修改同步对象的状态,如下所示:

  • 信号灯对象的计数减少1,如果其计数为零,则将信号量的状态设置为非终止。
  • Mutex、自动重置事件和更改通知对象的状态设置为非终止。
  • 同步计时器的状态设置为非终止。
  • 手动重置事件、手动重置计时器、进程、线程和控制台输入对象的状态不受 wait 函数的影响。

等待函数并创建 Windows

使用等待函数和直接或间接创建 windows 的代码时需要小心。 如果线程创建了任何窗口,则它必须处理消息。 消息广播将发送到系统中的所有窗口。 如果有使用 wait 函数且没有超时间隔的线程,系统会死锁。 间接创建 windows 的代码的两个示例是 DDE 和 CoInitialize 函数。 因此,如果有创建 windows 的线程,请使用 MsgWaitForMultipleObjectsMsgWaitForMultipleObjectsEx,而不要使用其他等待函数。