Windows 内核对象(二) 信号状态
Signal状态
以下内核对象中有一个Signal对象
- 进程内核对象
线程内核对象
- 进程和线程内核对象在初始化的时候, Signal为FALSE
- 等到它们运行完成, Signal为TRUE
- 进程和线程内核对象就进入
可受信(可接受信号)状态 - 进程和线程内核对象的Signal状态是系统来控制的
- 标准输入输出流对象
- 事件内核对象
- 互斥体
- 信号
- 可等待计时器
作业
- 以上这些有两种方式可以改变Signal状态
- 可以让操作系统来管控
- 也可以人工进行修改
使用
WaitForSingleObject来等待单个内核对象的信号状态- 它会让当前执行的线程进入
不可调度状态 - 等待指定时间, 或等到SIGNAL变为TRUE
它的返回值
- WAIT_TIMEOUT 等待超时
- WAIT_FAILED 等待失败, 需要调用GetLastError
- WAIT_OBJECT_0 等待完成, 指定的对象变为有信号了
- WAIT_ABANDONED 等待Mutex(互斥体)对象, 具体稍候了解
- 当使用该函数时需要注意, 如果内核对象的Signal状态是系统管理的
- 那么它将会把
可受信状态取出, 并将内核对象设置为不可受信状态 - 它会改变内核对象的成员
它主要用于我们
进程和进程之间的同步- 比如, 守护进程
- 守护进程为父进程
- 被守护的进程为子进程
- 父进程等待子进程的状态, 当子进程可受信, 就在重新启动子进程
- 它会让当前执行的线程进入
使用
WaitForMultipleObjects来等待多个内核对象的信号状态- 它会让当前执行的线程进入
不可调度状态 - 等待指定时间, 或等到SIGNAL变为TRUE
它的返回值
WAIT_OBJECT_0 到 WAIT_OBJECT_0 + nCount - 1
- 也就是说, 返回值是一个范围
- 最大的返回是 WAIT_OBJECT_0 + nCount - 1
- nCount是要等待的内核对象数量
WAIT_ABANDONED_0 到 WAIT_ABANDONED_0 + nCount - 1
- 也是等待互斥体的, 稍候了解
- WAIT_TIMEOUT 等待超时
- WAIT_FAILED 等待失败, 需要调用GetLastError
- 它会让当前执行的线程进入
内核对象主要是用于跨进程的同步
Wait的三种结果
让我们用一段代码来观察
#include <Windows.h>
#include <process.h>
#include <tchar.h>
UINT WINAPI ThreadFunc(LPVOID lParam)
{
// 休眠5秒, 会获得 等待超时
// 注释掉此代码, 会获得 等待成功
Sleep(5000);
return 0;
}
INT _tmain()
{
_tsetlocale(0, TEXT(""));
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, NULL);
DWORD dwWaitRet = -1;
//dwWaitRet = WaitForSingleObject(hThread, INFINITE); // 等待30天
dwWaitRet = WaitForSingleObject(hThread, 1000); // 等等1秒
switch (dwWaitRet)
{
// hThread 为INVALID_HANDLE_VALUE, 等待超时
case WAIT_TIMEOUT:
_tprintf(TEXT("等待超时!\n"));
break;
case WAIT_OBJECT_0:
_tprintf(TEXT("等待成功!\n"));
break;
// hThread 为NULL, 等待失败
case WAIT_FAILED:
_tprintf(TEXT("等待失败!\n"));
break;
default:
break;
}
CloseHandle(hThread);
return 0;
}注意:
当等待的HANDLE为NULL时, 会等待失败
当等待的HANDLE为INVALID_HANDLE_VALUE时, 会等待超时
如果等待时间为INFINITE, HANDLE为INVALID_HANDLE_VALUE, 线程将永久等待
Wait的注意事项
首先, 我们拿一个小例子测试WaitForMutipleObjects
#include <Windows.h>
#include <process.h>
#include <tchar.h>
UINT WINAPI ThreadFunc(LPVOID lParam)
{
// 休眠
Sleep((INT)lParam);
return 0;
}
/////// WaitForMultipleObjects
INT _tmain()
{
_tsetlocale(0, TEXT(""));
HANDLE hThreads[2] = { INVALID_HANDLE_VALUE };
hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (LPVOID)1000, 0, NULL);
hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (LPVOID)3000, 0, NULL);
DWORD dwWaitRet = -1;
//dwWaitRet = WaitForMultipleObjects(2, hThreads, FALSE, 200); // 等200毫秒
// 等待200毫秒, 等待超时
//dwWaitRet = WaitForMultipleObjects(2, hThreads, FALSE, 2000); // 等2秒
// 等待2秒, 等待成功
dwWaitRet = WaitForMultipleObjects(2, hThreads, FALSE, INFINITE); // 等永久
// 等待永久, 等待成功
switch (dwWaitRet)
{
case WAIT_TIMEOUT:
_tprintf(TEXT("等待超时!\n"));
break;
// WaitForMultipleObjects等待所有为TRUE时, WAIT_OBJECT_0永远不会进入
case WAIT_OBJECT_0:
_tprintf(TEXT("等待成功!\n"));
break;
case WAIT_FAILED:
_tprintf(TEXT("等待失败!\n"));
break;
default:
break;
}
CloseHandle(hThreads[0]);
CloseHandle(hThreads[1]);
return 0;
}当我们不等待所以线程完成的时候
- 等待时间内没有线程完成, 返回
等待超时 - 等待时间内有任意一条线程完成, 返回
等待成功
那如果要必须等到线程2执行结束应该怎么办?
我们写出如下代码:
#include <Windows.h>
#include <process.h>
#include <tchar.h>
UINT WINAPI ThreadFunc(LPVOID lParam)
{
// 休眠
Sleep((INT)lParam);
return 0;
}
/////// WaitForMultipleObjects
INT _tmain()
{
_tsetlocale(0, TEXT(""));
HANDLE hThreads[2] = { INVALID_HANDLE_VALUE };
hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (LPVOID)1000, 0, NULL);
hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (LPVOID)3000, 0, NULL);
DWORD dwWaitRet = -1;
// 等待指定线程结束
BOOL bLoop = TRUE;
while (bLoop)
{
dwWaitRet = WaitForMultipleObjects(2, hThreads, FALSE, 100); // 等100毫秒
switch (dwWaitRet)
{
case WAIT_TIMEOUT:
_tprintf(TEXT("等待超时! 进行下一次等待....\n"));
break;
case WAIT_OBJECT_0:
_tprintf(TEXT("线程 1 执行成功!\n"));
break;
case WAIT_OBJECT_0 + 1:
_tprintf(TEXT("线程 2 执行成功!\n"));
bLoop = FALSE;
break;
case WAIT_FAILED:
_tprintf(TEXT("等待失败!\n"));
break;
default:
break;
}
}
CloseHandle(hThreads[0]);
CloseHandle(hThreads[1]);
return 0;
}- 按照我们的设想, 这样很完美
- 但是, 它是错误的, 它会一直进入
WAIT_OBJECT_0分支
那这是为什么呢?
我们改写代码:
#include <Windows.h>
#include <process.h>
#include <tchar.h>
UINT WINAPI ThreadFunc(LPVOID lParam)
{
// 休眠
Sleep((INT)lParam);
return 0;
}
/////// WaitForMultipleObjects
INT _tmain()
{
_tsetlocale(0, TEXT(""));
HANDLE hThreads[2] = { INVALID_HANDLE_VALUE };
hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (LPVOID)1000, 0, NULL);
hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (LPVOID)3000, 0, NULL);
DWORD dwWaitRet = -1;
// 等待指定线程结束
BOOL bLoop = TRUE;
while (bLoop)
{
dwWaitRet = WaitForMultipleObjects(2, hThreads, FALSE, 100); // 等100毫秒
DWORD dwRet = WaitForSingleObject(hThreads[1], 10); // 等10毫秒
if (dwRet == WAIT_OBJECT_0 + 1)
_tprintf(TEXT("===> 线程 2 已经执行成功了!\n"));
switch (dwWaitRet)
{
case WAIT_TIMEOUT:
_tprintf(TEXT("等待超时! 进行下一次等待....\n"));
break;
case WAIT_OBJECT_0:
_tprintf(TEXT("线程 1 执行成功!\n"));
break;
case WAIT_OBJECT_0 + 1:
_tprintf(TEXT("线程 2 执行成功!\n"));
bLoop = FALSE;
break;
case WAIT_FAILED:
_tprintf(TEXT("等待失败!\n"));
break;
default:
break;
}
}
CloseHandle(hThreads[0]);
CloseHandle(hThreads[1]);
return 0;
}- 此时我们可以发现, 其实线程2已经成功完成了
- 但是我们却不能通过
WaitForMultipleObjects来获取到它的状态
所以, 一定要注意WaitForMultipleObjects等待多个内核对象但是并不等待所有内核对象完成的情况
未完待续...
如有错误,请提出指正!谢谢.
本文由 花心胡萝卜 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: 2017-07-02 at 04:29 am