工作积累之线程同步

来源:互联网 发布:java游戏高级编程 pdf 编辑:程序博客网 时间:2024/05/20 00:17
 工作中需要在一个线程A中控制另外一个线程B的运行、暂停和取消暂停(继续运行)、停止,涉及到线程同步问题;以前需要线程同步时都是从网上找现成的代码,从未自己认真研究过其中的原理,今天就认真的总结一下。有关线程同步互斥的控制方法,可以参考上一篇文章,这里直接叙述实现的代码。

实现上述的同步,使用了两个事件(Event)和两个互斥量(Mutex),分别为:

/** Events 事件 */ HANDLE      m_heventUnpaused;      //暂停HANDLE      m_heventThreadDead;    //停止/** Mutexes 互斥量*/HANDLE      m_hThreadRunningMutex;      //运行HANDLE      m_hGrabbingPauseFlagMutex;  //暂停还有两个布尔变量,分别用来控制运行于暂停,是上面的两个互斥量保护的资源,如下:bool       m_bPaused;              //暂停bool       m_bThreadRun;           //运行

先把上面各个变量初始化一下:
m_heventUnpaused     = CreateEvent( NULL, FALSE, FALSE, NULL );  //将暂停事件初始化为无信号状态m_heventThreadDead     = CreateEvent( NULL, FALSE, FALSE, NULL ); m_hThreadRunningMutex      = ::CreateMutex( NULL, FALSE, NULL );m_hGrabbingPauseFlagMutex  = ::CreateMutex( NULL, FALSE, NULL );    //将暂停互斥量初始化为无线程拥有该互斥量状态m_bPaused      = false;m_bThreadRun = false;


1. 首先是A线程如何控制B线程的运行:
下面的两段代码分别展示了如何使用互斥量来同步对变量m_bThreadRun的读写操作:
BOOL threadFlag()   //读操作{BOOL returnValue = false;DWORD dwRet = ::WaitForSingleObject( m_hThreadRunningMutex, 1000 );if( dwRet == WAIT_OBJECT_0 ){returnValue = m_bThreadRun;}::ReleaseMutex( m_hThreadRunningMutex );return returnValue;}; void setThreadRunningFlag( bool trueOrFalse )   //写操作{DWORD dwRet = ::WaitForSingleObject( m_hThreadRunningMutex, 5000 );  if( dwRet == WAIT_OBJECT_0 ){m_bThreadRun = trueOrFalse;}::ReleaseMutex( m_hThreadRunningMutex );return;};


然后在A线程中创建B线程,并调用setThreadRunningFlag(true);代码:
setThreadRunningFlag( true );
AfxBeginThread( threadGrab, this );
再在B线程函数中循环调用threadFlag(),B线程就运行起来了,代码:
UINT threadBFunction(void* pParam){    while( threadFlag() )    {       ...    }    ...}


2.如何在A线程中控制B线程的暂停与取消暂停;
下面的两段代码分别展示了如何使用互斥量来同步对变量m_bPaused的读写操作:
BOOL grabbingPaused(){BOOL returnValue = false;DWORD dwRet = ::WaitForSingleObject( m_hGrabbingPauseFlagMutex, 5000 );if( dwRet == WAIT_OBJECT_0 ){returnValue = m_bPaused;}::ReleaseMutex( m_hGrabbingPauseFlagMutex );return returnValue;};void setGrabbingPausedFlag( bool trueOrFalse ){DWORD dwRet = ::WaitForSingleObject( m_hGrabbingPauseFlagMutex, 1000 );if( dwRet == WAIT_OBJECT_0 ){m_bPaused = trueOrFalse;}::ReleaseMutex( m_hGrabbingPauseFlagMutex );return;};


初始时变量m_bPaused设为false;
m_bPaused = false;
然后在B线程函数中有如下代码:
UINT threadBFunction(void* pParam){    while( threadFlag() )    {        if( grabbingPaused() )     {           DWORD dw = WaitForSingleObject( m_heventUnpaused, INFINITE );       ASSERT( dw == WAIT_OBJECT_0  );       }     ...  //计算处理    }    ...}


因为m_bPaused=false,所以代码是无法执行到if语句中去的;一直在执行“计算处理”的代码;当在A线程中调用了PauseCapture函数时,
B线程的执行就会暂停下来,我们先看看PauseCapture函数的代码:
bool PauseCapture(){if ( grabbingPaused() ){setGrabbingPausedFlag ( false );}else{setGrabbingPausedFlag ( true );}if( !grabbingPaused() ){SetEvent( m_heventUnpaused );     }return true;}


看到了吧,此时调用PauseCapture函数,会首先执行setGrabbingPausedFlag ( true );语句,把m_bPaused置为true;此时在B线程函数中就
可以进入if语句了;然后if语句中有WaitForSingleObject( m_heventUnpaused, INFINITE );这一行代码,大家还记得初始化时,
m_heventUnpaused被初始化成为了无信号状态,所以B线程就在这里无限期等待m_heventUnpaused变为有信号状态;B线程就暂停了;
当用户再次调用PauseCapture函数,会首先执行setGrabbingPausedFlag ( false );语句,把m_bPaused置为false;然后由于m_bPaused是
false,语句SetEvent( m_heventUnpaused );被调用,m_heventUnpaused就变为有信号状态了,然后B线程就可以继续往下执行了。
3.如何在A线程中控制B线程的停止;
调用函数StopCapture来停止B线程;
bool StopCapture( void){// Inform the grab thread to quitif ( threadFlag() ){setThreadRunningFlag ( false );DWORD dwRet = WaitForSingleObject( m_heventThreadDead, 5000 );ASSERT( dwRet == WAIT_OBJECT_0 );}...}


setThreadRunningFlag ( false );使得B线程函数中的while( threadFlag() )条件不成立,退出循环;
B线程函数:重点是最后一行代码;SetEvent( m_heventThreadDead );将m_heventThreadDead事件置为有信号状态;
UINT threadBFunction(void* pParam){    while( threadFlag() )    {        if( grabbingPaused() )     {           DWORD dw = WaitForSingleObject( m_heventUnpaused, INFINITE );       ASSERT( dw == WAIT_OBJECT_0  );       }     ...  //计算处理    }    SetEvent( m_heventThreadDead );}


然后在StopCapture函数中又调用了WaitForSingleObject( m_heventThreadDead, 5000 );ASSERT( dwRet == WAIT_OBJECT_0 );两条语句,
来确认B线程已经结束;
原创粉丝点击