来自MSDN
作用:
一直等待到所指定的对象生命周期终止或者超时时间到达。
若要进入一个能够提出警告的等待状态,则使用WaitForSingleObjectEx函数。等待多个对象,使用WaitForMultipleObjects函数。
语法:
C++
DWORD WINAPI WaitForSingleObject{
_In_ HANDLE hHandle,
_In_ DWORD dwMilliseconds
};
参数:
hHandle[in]
指向一个对象的句柄。句柄所指向的对象类型清单可参考后面的附加区。
如果该句柄被关闭了,但是等待仍处于挂起状态,该函数的行为会转为未知。
该句柄必须具备SYNCHRONIZE访问权限。了解更多信息,参考标准访问权限。
dwMilliseconds[in]
超时时间间隔,以ms为单位。若设定了一个非零值,则函数将一直等待到该对象生命周期终止或所设定的超时时间到达。如果dwMilliseconds为零,那么如果该对象没有终止,函数不会进入等待状态,它总是会立即返回。如果dwMilliseconds设置为INFINITE,那么函数只有在该对象生命周期终止时才会返回。
Windows XP,Windows Server 2003,Windows Vista,Windows 7, Windows Server 2008以及Windows Server2008 R2:在这些系统上面dwMilliseconds值也包含了低功耗状态时的时间。比如,当计算机在睡眠时,超时时间仍然在倒计时。
Windows 8, Windows Server 2012, Windows 8.1, Windows Server 2012 R2, Windows 10以及Windows Server 2016:在这些系统上面dwMilliseconds值不包含低功耗状态时的时间。比如,当计算机在睡眠时,超时时间会停止倒计时。
返回值:
若函数成功返回,则返回值指向的是引起函数返回的事件。它可能是以下值中的一种:
返回代码/值 | 描述 |
WAIT_ABANDONED 0x00000080L | 在mutex对象所属线程终止前,指定的mutex对象不会被线程释放。mutex对象属于调用线程并且mutex的状态会被设置为非终止状态。 如果mutex正在保护永久状态信息,应该不停的去检查一致性。 |
WAIT_OBJECT_0 0x00000000L | 指定对象的状态为终止状态 |
WAIT_TIMEOUT 0x00000102L | 超时时间到达,且对象状态为非终止状态。 |
WAIT_FAILED (DWORD)0xFFFFFFFF | 函数已经失败。若要获得更多错误信息,参考GetLastError |
附加:
WaitForSingleObject函数检查指定对象的当前状态。若对象的状态为非终止状态,那么调用线程进入等待状态一直到该对象终止或超时时间到达为止。
该函数修改同步对象的某些类型的状态,且修改操作只有在该对象由于处于终止状态导致的函数返回时才会发生。比如,信号对象的数量逐个递减时。
WaitForSingleObject函数能够等待以下对象:
1.改变提示(change notification)
2.控制台输入(Console input)
3.内存资源提示(Memory resource notification)
4.互斥(mutex)
5.进程(process)
6.信号(Semaphore)
7.线程(thread)
8.可等待的定时器(Waitable timer)
当间接或直接地调用等待函数以及代码创建窗口时需要小心使用该函数。如果线程创建了窗口,那么它必须处理许多消息。消息广播到系统中的所有窗口。此时线程使用一个没有超时时间间隔的等待函数可能会引起系统死锁。DDE以及CoInitialize函数就是两个简介的创建窗口的例子。因此,如果有一个线程创建了窗口,请使用MsgWaitForMultipleObjects或者MsgWaitForMultipleObjectsEx。而不是WaitForSingleObject。
使用Mutex对象的样例:
由于多线程或多进程的同步访问而使用一个mutex对象来保护共享资源。每个进程在执行代码访问该共享资源前都必须等待mutex量。比如,如果几个线程共享一个数据库,这些线程可能会使用一个mutex对象设置在一个时刻只允许一个线程访问数据库。
以下实例就是使用CreateMutex函数创建一个mutex对象以及CreateThread函数创建一个工作线程。
当该函数有一个线程要写数据库时,首先它要使用WaitForSingleObject函数申请mutex量。线程获取到mutex的权限后,它才会对数据库进行写入操作,随后使用ReleaseMutex函数释放该mutex。
#include <windows.h>
#include <stdio.h>
#define THREADCOUNT 2
HANDLE ghMutex;
DWORD WINAPI WriteToDatabase(LPVOID);
int main(void)
{
HANDLE aThread[THREADCOUNT];
DWORD ThreadID;
int i;
// Create a mutex with no initial owner
ghMutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (ghMutex == NULL)
{
printf("CreateMutex error: %d\n", GetLastError());
return 1;
}
// Create worker threads
for (i = 0; i < THREADCOUNT; i++)
{
aThread[i] = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE)WriteToDatabase,
NULL, // no thread function arguments
0, // default creation flags
&ThreadID); // receive thread identifier
if (aThread[i] == NULL)
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
}
// Wait for all threads to terminate
WaitForMultipleObjects(THREADCOUNT, aThread, true, INFINITE);
// Close thread and mutex handles
for (i = 0; i < THREADCOUNT; i++)
CloseHandle(aThread[i]);
CloseHandle(ghMutex);
getchar();
return 0;
}
DWORD WINAPI WriteToDatabase(LPVOID lpParam)
{
// lpParam not used in this example
UNREFERENCED_PARAMETER(lpParam);
DWORD dwCount = 0, dwWaitResult;
// Request ownership of mutex.
while (dwCount < 20)
{
dwWaitResult = WaitForSingleObject(
ghMutex, // handle to mutex
INFINITE); // no time-out interval
switch (dwWaitResult)
{
// The thread got ownership of the mutex
case WAIT_OBJECT_0:
__try {
// TODO: Write to the database
printf("Thread %d writing to database...\n",
GetCurrentThreadId());
dwCount++;
}
__finally {
// Release ownership of the mutex object
if (!ReleaseMutex(ghMutex))
{
// Handle error.
}
}
break;
// The thread got ownership of an abandoned mutex
// The database is in an indeterminate state
case WAIT_ABANDONED:
return FALSE;
}
}
return TRUE;
}
该样例使用了一个异常结构体来确保线程正常释放了mutex对象。不论__try块是怎么终止的,__finally代码块都会执行(除非__try块含有一个TerminateThread的函数调用)。这防止了mutex对象被无意丢弃。
如果一个Mutex被丢弃,那么拥有该Metex的线程在终止前是不能够正常释放它的。在这种情况下,共享资源的状态是不明确的,如果继续使用该Mutex则可能会引起潜在的严重错误。一些应用程序可能试图恢复资源到一个一致的状态。这个样例只是简单的返回一个错误同时停止使用Mutex。要了解更多信息,可参考mutex对象。
输出: