Windows中线程的基础知识和简单应用----Thread的等待

在上一篇文章中讲到了线程的生死。对于线程来说,创建是最简单的;结束相对就要复杂一下了,因为要考虑让线程自己终止,这样才能更好的释放线程所咱用的资源。个人认为对于线程而言最难之处要属线程的同步。这就像是一位领导者,在管理下属。用好的管理方式能让下属相互协作,事半功倍;不好的管理方式会让下属手忙脚乱,重复劳动互相等待。致使工作无法进行。

 

在《Thread的生死》中,已经领略到了线程的随机性。也就是说,当我们依次创建了三个线程后,线程并不一定能按照创建的顺序依次工作。请看下面的例子。

 

class SampleThread

{

Public:

   SampleThread();

   ~SampleThread();

   Initialize();

   Public:

      int m_count;

   Private:

      HANDLE m_hHand_One;

      HANDLE m_hHand_Two;

      HANDLE m_hHand_Three;

};

 

DWORD WINAPI ThreadFunc_One(LPVOID pPram)

{

       SampleThread *p = (SampleThread*) pPram

    p-> m_count = p-> m_count + 1;

       return 0;

}

 

DWORD WINAPI ThreadFunc_Two(LPVOID pPram)

{

       SampleThread *p = (SampleThread*) pPram

    p-> m_count = p-> m_count - 2;

       return 0;

}

 

DWORD WINAPI ThreadFunc_Three(LPVOID pPram)

{

       SampleThread *p = (SampleThread*) pPram

    p-> m_count = p-> m_count + 3;

       return 0;

}

 

SampleThread::SampleThread()

: m_count(2)

, m_hHand_One(NULL)

, m_hHand_Two(NULL)

, m_hHand_Three(NULL)

{}

 

SampleThread::~SampleThread()

{

   if(NULL != m_hHand_One) CloseHandle(m_hHand_One);

if(NULL != m_hHand_Two) CloseHandle(m_hHand_Two);

if(NULL != m_hHand_Three) CloseHandle(m_hHand_Three);

}

SampleThread::Initialize()

{

   m_hHand_One = ::CreateThread(NULL, 0, ThreadFunc_One, this, TRUE, 0);

m_hHand_Two = ::CreateThread(NULL, 0, ThreadFunc_Two, this, TRUE, 0);

m_hHand_Three = ::CreateThread(NULL, 0, ThreadFunc_Three, this, TRUE, 0);

 

_cwprintf(_T("%s%d/n"), _T("m_count is "), m_count);

}

按上述的代码,如果线程能按照创建顺序执行的话,分析结果是:m_count的初始值是2,那么在ThreadFunc_Onem_count值是3,在ThreadFunc_Twom_count值是1,在ThreadFunc_Threem_count值是4

    下面让我们看看实际执行的结果。

这个事实再次告诉我们,线程运行的结果实在不可预测。那么,怎么才能让线程变得可以预测呢。也就是说让线程的运行结果达到我们的预期值呢。这就是,我们要讨论的问题,线程的同步。

    首先让我们熟悉几个专有名词,在日后的学习中是必不可少的。

同步:当主线程A创建工作B时,主线程A一直等到工作线程B结束,然后再继续执行其他的操作。对应的英文:Synchronous

异步:当主线程A创建工作B时,主线程A只负责创建工作线程B,然后径自继续执行其他的操作。对应的英文:Asynchronous

已通知态:当一个线程返回后,那么可以说这个线程处于已通知态。

未通知态:当一个线程在运行时,那么可以说这个线程处于未通知态。

 

在改变m_count值时,我们希望能按照线程的创建顺序去执行。希望ThreadFunc_Two能在线程ThreadFunc_One结束后调度,并且ThreadFunc_Three能在ThreadFunc_Two调度后调度。也就是说,我们所期望的就是等待。一个线程在等待另一个线程结束后再被调度。对于线程来说,Windows操作系统给我们提供了WaitForSingleObject函数。具体声明如下:

DWORD WaitForSingleObject( HANDLE hHandle,

                                        DWORD dwMilliseconds );

hHandle:是一个对象句柄。

dwMilliseconds:等待的时间。

这里需要对返回值进行详细的描述。请看下表:

返回值

描述

WAIT_OBJECT_0

当等待对象从未通知态变为已通知态。

WAIT_TIMEOUT

当等待对象从未通知态变为已通知态前,等待时间终止了。

WAIT_FAILED

当等待对象是一个无效句柄时。

上述代码可以修改为如下状态。

 

DWORD WINAPI ThreadFunc_One(LPVOID pPram)

{

       SampleThread *p = (SampleThread*) pPram

    p-> m_count = p-> m_count + 1;

       return 0;

}

 

DWORD WINAPI ThreadFunc_Two(LPVOID pPram)

{

    WaitforSingleObject(p-> m_hHand_One, INFINITE);

       SampleThread *p = (SampleThread*) pPram

    p-> m_count = p-> m_count - 2;

       return 0;

}

 

DWORD WINAPI ThreadFunc_Three(LPVOID pPram)

{

WaitforSingleObject(p-> m_hHand_Two, INFINITE);

       SampleThread *p = (SampleThread*) pPram

    p-> m_count = p-> m_count + 3;

       return 0;

}

 

INFINITE这个参数告诉WaitforSingleObject函数,无期限等待。这时候,只有当ThreadFunc_One返回后,ThreadFunc_Two才有机会得到CPU的时间片;当ThreadFunc_Two返回后,ThreadFunc_Three才有机会得到CPU的时间片。这样就保证了,线程运行的顺序和我们的期待值相同。

Windows系统中还有一个等待多个对象的函数,声明如下:

 

 

 

DWORD WaitForMultipleObjects(  DWORD nCount,

                                             CONST HANDLE* lpHandles,

                                             BOOL fWaitAll,

                                             DWORD dwMilliseconds );

nCount:等待对象的数量。

lpHandles:一个存放等待对象句柄的数组地址。

fWaitAll:如果该参数是TRUE,那么lpHandles中的等待的所有对象都变成已通知状态,函数才返回;如果设置为FALSE,那么只要有一个等待对象变为已通知状态,该函数就返回。

有了这个函数,上面的代码可以修改成:

DWORD WINAPI ThreadFunc_Three(LPVOID pPram)

{

    HANDLE hThreads[2];

    hThreads[0] = m_hHand_One;

    hThreads[1] = m_hHand_Two;

WaitforMultipleObject(2, hThreads, TRUE, INFINITE);

       SampleThread *p = (SampleThread*) pPram

    p-> m_count = p-> m_count + 3;

       return 0;

}

 

通过这个例子不知道有没有看出什么事情出来。同步的根本就是等待!上面的例子等待的是线程对象,除此之外在做线程同步控制的时候还可以等待事件(Event)、互斥量(Mutex)、信号量(Semaphore)。稍后会一一拿出来讨论。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值