KeWaitForMultipleObjects 函数 (wdm.h)

KeWaitForMultipleObjects 例程将当前线程置于可警报或不可检测的等待状态,直到将任意或所有多个调度程序对象设置为信号状态,或 (选择性地) ,直到等待超时。

语法

NTSTATUS
KeWaitForMultipleObjects (
    ULONG Count,
    PVOID Object[],
    WaitType,
    KWAIT_REASON WaitReason,
    KPROCESSOR_MODE WaitMode,
    BOOLEAN Alertable,
    PLARGE_INTEGER Timeout,
    PKWAIT_BLOCK WaitBlockArray
    );

参数

[in] Count

要等待的对象数。 此参数指定 Object 参数指向的数组中的元素数。

[in] Object

指向调度程序对象的指针数组的指针,这些对象 (调用方为其提供存储的事件、互斥体、信号灯、线程和计时器) 。 指针数组和调度程序对象都必须驻留在非分页系统内存中。 有关详细信息,请参阅“备注”。

[in] WaitType

要执行的等待操作的类型。 指定任一 WaitAll,指示所有指定的对象必须在满足等待前达到信号状态;或 WaitAny,指示任何一个对象都必须在满足等待之前达到信号状态。

[in] WaitReason

等待的原因。 驱动程序应将此值设置为 Executive ,如果驱动程序代表用户执行工作并在用户线程的上下文中运行,则设置为 UserRequest

[in] WaitMode

调用方是在 KernelMode 还是 UserMode 中等待。 中间和最低级别驱动程序应指定 KernelMode。 如果等待的对象集包含互斥体,则调用方必须指定 KernelMode

[in] Alertable

一个布尔值,指示线程处于等待状态时是否可以发出警报。

[in, optional] Timeout

指向超时值的指针,该值指定要完成等待的绝对时间或相对时间(以 100 纳秒为单位)。

正值指定相对于 1601 年 1 月 1 日绝对时间。 负值指定相对于当前时间的间隔。 绝对过期时间跟踪系统时间中的任何更改;相对过期时间不受系统时间更改的影响。

如果 *Timeout = 0,则例程返回而不等待。 如果调用方提供 NULL 指针,则例程将无限期等待,直到将任何或所有调度程序对象设置为信号状态。 有关更多信息,请参见下面的“备注”部分。

[out, optional] WaitBlockArray

指向调用方分配 的KWAIT_BLOCK数组的 指针。 如果 Count<= THREAD_WAIT_OBJECTS,则 WaitBlockArray 可以为 NULL。 否则,此参数必须指向 大小 为 (KWAIT_BLOCK) *计数 字节的内存缓冲区。 例程在执行等待操作时使用此缓冲区进行记录保留。 WaitBlockArray 缓冲区必须驻留在非分页系统内存中。 有关详细信息,请参阅“备注”。

返回值

KeWaitForMultipleObjects 可以返回下列值之一:

返回代码 说明
STATUS_SUCCESS WaitType 参数指定的调用方和 Object 数组中的所有调度程序对象都已设置为信号状态。
STATUS_ALERTED 等待中断,无法向调用线程发送警报。
STATUS_USER_APC 等待中断,无法将用户异步过程调用 (APC) 传送到调用线程。
STATUS_TIMEOUT 在满足指定的等待条件集之前发生超时。 当指定了显式超时值零时,可以返回此值,但无法立即满足指定的等待条件集。
通过STATUS_WAIT_63STATUS_WAIT_0 WaitType 指定的调用方和 Object 数组中的一个调度程序对象已设置为信号状态。 返回值的低 6 位对满足等待的 对象的从零开始的索引进行编码。
通过STATUS_ABANDONED_WAIT_63 STATUS_ABANDONED_WAIT_0 调用方试图等待已放弃的互斥体。 返回值的下六位对 Object 数组中互斥体从零开始的索引进行编码。

请注意,NT_SUCCESS宏会将所有这些状态值识别为“成功”值。

注解

每个线程对象都有一个内置的等待块数组,可用于等待同时设置多个对象。 应尽可能在等待多次操作中使用内置的等待块数组,因为无需分配额外的等待块存储,以后无需解除分配。 但是,如果必须同时等待的对象数大于内置等待块的数目,请使用 WaitBlockArray 参数指定要在等待操作中使用的备用等待块集。 驱动程序只需为 WaitBlockArray 分配足够大的内存缓冲区。 不需要初始化缓冲区;但是,必须从非分页系统内存中分配它。 如果 WaitMode 参数为 UserMode,则不能在本地堆栈上分配 WaitBlockArray 缓冲区,因为堆栈可能会交换内存。 驱动程序可以将此缓冲区视为不透明的结构,并且可以在例程返回后释放它。 如果 Count> MAXIMUM_WAIT_OBJECTS 或 WaitBlockArrayNULLCount> THREAD_WAIT_OBJECTS,系统会 0xC (MAXIMUM_WAIT_OBJECTS_EXCEEDED) 发出 Bug 检查

检查每个指定对象的当前状态,以确定是否可以立即满足等待。 如果对对象执行必要的副作用,则返回适当的值。

如果无法立即满足等待,并且未指定超时值或非零超时值,则当前线程处于等待状态,并选择一个新线程在当前处理器上执行。 如果未提供 超时 ,则调用线程将保持等待状态,直到满足 ObjectWaitType 指定的条件。

如果指定了 Timeout ,则当给定的间隔过期时,如果未满足任何指定的等待条件,则将自动满足等待。

如果超时值为 0,则允许测试一组等待条件,如果有条件地执行任何副作用(如果可以立即满足等待),就像获取互斥体一样。

超时间隔相对于系统时钟进行测量,操作系统检测超时间隔结束的准确性受系统时钟粒度的限制。 有关详细信息,请参阅 计时器准确性

Alertable 参数确定线程何时可以发出警报,其等待状态因此中止。 有关详细信息,请参阅 等待和 APC

Objects 参数指向的数组必须驻留在非分页系统内存中。 通常,驱动程序为本地堆栈上的 Objects 数组分配存储。 无论 WaitMode 参数的值如何,都可以在本地堆栈上分配 Objects 数组。

Objects 数组中的元素指向的调度程序对象必须驻留在非分页系统内存中。 如果 WaitMode 参数为 UserMode,则可以在等待期间交换内核堆栈。 因此,在使用 UserMode 参数调用 KeWaitForMultipleObjects 时,调用方不得尝试在堆栈上传递参数。 如果在堆栈上分配事件,则必须将 WaitMode 参数设置为 KernelMode

当传递给 KeWaitForMultipleObjectsObject 参数是互斥体时,需要特别注意。 如果等待的调度程序对象是互斥体,则 APC 传递与等待期间所有其他调度程序对象的传递相同。 但是, 在 KeWaitForMultipleObjects 返回并STATUS_SUCCESS并且线程实际持有互斥体之后,仅传递特殊的内核模式 APC。 禁用所有其他 APC(内核模式和用户模式)的传递。 在释放互斥体之前,对 APC 的传递限制一直存在。

WaitMode 参数为 UserModeAlertableTRUE 时,检查 KeWaitForMultipleObjects 的返回值尤其重要,因为 KeWaitForMultipleObjects 可能会提前返回状态为 STATUS_USER_APC 或 STATUS_ALERTED。

用户可以中止的所有长期等待都应为 UserMode 等待, Alertable 应设置为 FALSE

如果可能,Alertable 应设置为 FALSE,WaitMode 应设置为 KernelMode,以降低驱动程序的复杂性。 当等待是长期等待时,主要例外。

互斥体只能以递归方式获取 MINLONG 时间。 如果超出此限制,则例程将引发STATUS_MUTANT_LIMIT_EXCEEDED异常。

KeWaitForMultipleObjects 的调用方可以在 IRQL <= DISPATCH_LEVEL 运行。 但是,如果 Timeout = NULL 或 *Timeout != 0,则调用方必须在 IRQL <= APC_LEVEL 且在非比特线程上下文中运行。 (如果 Timeout != NULL 且 *Timeout = 0,则调用方必须在 IRQL <= DISPATCH_LEVEL.)

要求

要求
最低受支持的客户端 从 Windows 2000 开始可用。
目标平台 通用
标头 wdm.h(包括 Wdm.h、Ntddk.h、Ntifs.h)
Library NtosKrnl.lib
DLL NtosKrnl.exe
IRQL 请参见“备注”部分。
DDI 符合性规则 HwStorPortProhibitedDDI (storport) IrpProcessingComplete (wdm) IrqlKeWaitForMultipleObjects (wdm) SpNoWait (storport)

另请参阅

ExInitializeFastMutex

KeInitializeEvent

KeInitializeMutex

KeInitializeSemaphore

KeInitializeTimer

KeWaitForSingleObject