书籍:《Visual C++ 2017从入门到精通》的2.3.8 Win32控件编程
环境:visual studio 2022
WaitForSingleObject() 是 Windows API 中用于同步操作的核心函数,主要用于等待一个内核对象(如线程、进程、事件、互斥量等)进入有信号状态(Signaled)。以下是其详细解析:
一、函数原型
DWORD WaitForSingleObject(
HANDLE hHandle, // 内核对象句柄
DWORD dwMilliseconds // 等待时间(毫秒)
);
二、参数说明
-
hHandle- 类型:
HANDLE - 含义:指向目标内核对象的句柄。
- 有效对象类型:
- 线程(Thread)
- 进程(Process)
- 事件(Event)
- 互斥量(Mutex)
- 信号量(Semaphore)
- 权限要求:句柄必须具有
SYNCHRONIZE访问权限,否则函数调用失败。
- 类型:
-
dwMilliseconds- 类型:
DWORD(32 位无符号整数) - 取值:
INFINITE(0xFFFFFFFF):无限等待,直到对象变为有信号状态。0:立即返回当前对象状态,不阻塞线程。- 其他正整数:等待的毫秒数(如
5000表示等待 5 秒)。
- 类型:
三、返回值
函数返回一个 DWORD 类型的状态码,表示等待结果:
| 返回值 | 含义 |
|---|---|
WAIT_OBJECT_0 (0x0) | 对象变为有信号状态。 |
WAIT_TIMEOUT (0x102) | 等待超时(仅在 dwMilliseconds 非 INFINITE 时发生)。 |
WAIT_FAILED (0xFFFFFFFF) | 函数调用失败,需通过 GetLastError() 获取错误码(如无效句柄、权限不足)。 |
四、典型应用场景
-
等待线程结束
主线程通过等待子线程句柄变为有信号状态,确保子线程完成任务后再继续执行:HANDLE hThread = CreateThread(...); WaitForSingleObject(hThread, INFINITE); // 无限等待子线程结束 CloseHandle(hThread); -
事件驱动编程
等待事件对象被触发(如用户输入、数据到达):HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // 其他线程触发事件:SetEvent(hEvent); DWORD result = WaitForSingleObject(hEvent, 5000); // 最多等待5秒 if (result == WAIT_OBJECT_0) { // 事件触发,执行操作 } -
互斥量同步
等待互斥量可用(避免资源竞争):HANDLE hMutex = CreateMutex(NULL, FALSE, NULL); WaitForSingleObject(hMutex, INFINITE); // 等待互斥量释放 // 访问共享资源 ReleaseMutex(hMutex);
五、关键注意事项
-
句柄有效性
- 若
hHandle无效(如已关闭或从未创建),函数返回WAIT_FAILED。 - 需确保句柄具有
SYNCHRONIZE权限。
- 若
-
对象状态重置
- 自动重置事件(AutoResetEvent):当一个等待线程被唤醒后,对象自动变为无信号状态。
- 手动重置事件(ManualResetEvent):需显式调用
ResetEvent()重置状态。
-
线程阻塞与CPU占用
- 等待期间线程处于挂起状态,不占用 CPU 资源。
- 避免在 UI 线程中无限等待(如
INFINITE),可能导致界面假死。
-
超时机制
- 合理设置超时时间,防止永久阻塞。
- 超时后需检查对象状态(如通过
WaitForSingleObject再次检测)。
六、错误处理
若函数返回 WAIT_FAILED,可通过 GetLastError() 获取错误码:
DWORD result = WaitForSingleObject(hHandle, 1000);
if (result == WAIT_FAILED) {
DWORD err = GetLastError();
printf("WaitForSingleObject failed: %lu\n", err);
}
常见错误码:
ERROR_INVALID_HANDLE(6):句柄无效。ERROR_ACCESS_DENIED(5):权限不足。
七、与其他函数对比
| 函数 | 功能 | 适用场景 |
|---|---|---|
WaitForSingleObject | 等待单个内核对象变为有信号状态 | 单一同步对象(如线程、事件) |
WaitForMultipleObjects | 等待多个内核对象中的任意一个或全部变为有信号 | 多路复用同步(如同时等待事件和信号量) |
八、代码示例
#include <windows.h>
#include <stdio.h>
int main() {
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // 手动重置事件
if (hEvent == NULL) {
printf("CreateEvent failed: %lu\n", GetLastError());
return 1;
}
// 模拟异步操作(如后台任务)
printf("Waiting for event...\n");
DWORD result = WaitForSingleObject(hEvent, 3000); // 等待3秒
switch (result) {
case WAIT_OBJECT_0:
printf("Event triggered!\n");
break;
case WAIT_TIMEOUT:
printf("Timeout: Event not triggered.\n");
break;
case WAIT_FAILED:
printf("Error occurred.\n");
break;
}
CloseHandle(hEvent);
return 0;
}
九、总结
WaitForSingleObject() 是 Windows 同步编程的基础函数,通过阻塞线程直到目标内核对象变为有信号状态,实现线程间协调。
核心要点:
- 确保句柄有效且具有同步权限。
- 合理设置超时时间,避免无限阻塞。
- 根据对象类型(事件、互斥量等)正确处理状态重置。
- 结合错误处理提升代码健壮性。
通过合理使用该函数,可以构建高效、可靠的多线程和异步应用程序。



3万+

被折叠的 条评论
为什么被折叠?



