您的位置:首页 > 其它

线程同步——内核对象实现线程同步——等待函数

2014-08-16 11:03 204 查看
对于内核对象实现线程同步,不得不提三点:
1)大多数内核对象既有触发也有未触发两个状态
比如:进程、线程、作业、文件流、事件、可等待的计时器、信号量、互斥量
2)等待函数:等待函数使线程自愿进入等待状态,直到指定的内核对象变为触发状态为止,
说道等待我们最喜欢不过了,因为这样不会浪费我们宝贵的CPU时间。
3)对于自动重置对象来说,当对象被触发时,函数会自动检测到(手动重置对象为触发是,函数也能检测到),
并开始执行,但是在函数会在返回之前使事件变为非触发状态。

下面介绍一下最常见的几个等待函数:
1):
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );
第一个参数hHandle用来标识要等待的内核对象,第二个人参数dwMilliseconds用来标识自愿花多长时间等待。

下面的函数是告诉系统,线程希望一直等待,直到线程所在的进程终止或hProcess标识的对象变为触发状态
WaitForSingleObject(hProcess,INFINITE);

关于等待函数的返回问题,我们看下面代码:
DWORD dw = WaitForSingleObject(hProcess,5000) ;

switch(dw)
{
case WAIT_OBJECT_0:
// 线程等待对象被触发,也就是说线程还没到5000的等待时间就开始工作啦
break;

case WAIT_TIMEOUT:
//线程等待超时,线程在5000的时间还是没有等到对象被触发,但是时间到了,线程也要开始工作啦
break;

case WAIT_FAILED:
//线程传人了一个无效的句柄,这时后果可能就无法预料了
break;
}

2)
DWORD WaitForMultipleObjects(
DWORD nCount,
CONST * HANDLE  phObjects,
BOOL bWaitAll ,
DWORD dwMilliseconds) ;
第一个参数nCount表示我们希望检测内核对象的数量,这个值必须在 1到 MAXIMUM_WAIT_OBJECTS 最大是64,
我相信已经够多了,真的需要那么多时就不应该用这种方法了哦
第二个参数phObjects,是一个指针,指向内核对象句柄的数组
第三个参数bWaitAll是告诉函数,我们希望用哪种方式。如果这个函数传入 TRUE ,
那么在所有的内核对象被触发之前,函数不会允许调用线程执行。
第四个参数dwMilliseconds就是和WaitForSingleObject的第二个参数一样了,我们最多等待多久,
当然也可以传入INFINITE表示在满足条件前愿意一直等待。

关于WaitForMultipleObjects的返回值,我们也一起来看看代码哇:

HANDLE h[3];
h[0] = hProgress1 ;
h[1] = hProgress2 ;
h[2] = hProgress3 ;

DWORD dw = WaitForMultipleObjects(3,h,FALSE,5000) ;
switch(dw)
{
case WAIT_FAILED:
//传入无效句柄,后果就不多说了哈
break;

case WAIT_TIMEOUT:
//线程等待超时,线程在5000的时间还是没有等到对象被触发,但是时间到了,线程要开始工作啦
break;

case WAIT_OBJECT_0 + 0:
//对象h[0]为触发状态
break;

case WAIT_OBJECT_0 + 1:
//对象h[1]为触发状态
break;

case WAIT_OBJECT_0 + 2:
//对象h[2]为触发状态
break;
}
//这样写也有弊端,比如h[0] 和 h[1]同时为触发时,结果h[0]处理完就返回了
把下面代码DWORD WINAPI ThreadFunOne(PVOID pvParam) 线程中注释行运行,便可以体会体会了。

#include "windows.h"
#include "iostream"
using namespace std;
long g_x = 0 ;

// 定义一个事件对象1
// HANDLE g_hEvent1 ;
//
// 定义一个事件对象2
// HANDLE g_hEvent2;

HANDLE h[2];

//定义线程函数1
DWORD WINAPI ThreadFunOne(PVOID pvParam) ;

//定义线程函数2
DWORD WINAPI ThreadFunTwo(PVOID pvParam);

int main()
{

//创建一个手动重置的事件对象
h[0] = CreateEvent(NULL,FALSE,TRUE,NULL);

//创建一个手动重置的事件对象
h[1] = CreateEvent(NULL,FALSE,TRUE,NULL);

//把事件设为未触发状态
//    ResetEvent(g_hEvent);

//创建线程1
HANDLE hThreadOne = CreateThread(NULL,0,ThreadFunOne,0,0,NULL);
CloseHandle(hThreadOne);

//创建线程2
HANDLE hThreadTwo = CreateThread(NULL,0,ThreadFunTwo,0,0,NULL);
CloseHandle(hThreadTwo);

//让主线程先挂起,确保其它线程执行完成
Sleep(1000);
cout<<g_x<<endl;
return 0 ;
}

DWORD WINAPI ThreadFunOne(PVOID pvParam)
{
WaitForMultipleObjects(2,h,FALSE,INFINITE) ; //运行结果为2
//WaitForMultipleObjects(2,h,TRUE,INFINITE) ; //运行结果为1
g_x++;

return 0;
}

DWORD WINAPI ThreadFunTwo(PVOID pvParam)
{
Sleep(200);
WaitForSingleObject(h[1],INFINITE);
g_x++;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: