注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

永恒的遗失古都-亚特兰蒂斯

一个游戏开发者的个人博客。

 
 
 

日志

 
 

ThreadMonitor 线程监视器  

2015-09-29 20:11:17|  分类: 程序相关 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
本文由自由骑士笃志原创,可自由转载,若转载请保留此行声明。
简介
    它可以对一个线程进行状态监视,然后将得到的状态值通知给适当的监听者。通常来说它适合 生产者/消费者 设计模式,它允许支持多个消费者。
    例如我们VS中有线程窗口,则是可以通过线程监视器对线程进行管理,并及时获取线程状态,通知给窗口刷新,我们则可以获知当前的线程状态。

原理
    它保存一个变量值。然后该值允许被修改,作为线程之间的状态切换通知。线程可以在内部进行阻塞等待,或者在外部轮询检查。

扩展
    这个类当前支持的是多个消费者。但通常可以通过增加value的个数或者枚举类型,以达成多个生产者“或,且”条件限制。

补充知识
    pthread_cond_t 和 pthread_mutex_t同时使用的效果
    我们看段代码
    
pthread_mutex_t count_lock;
pthread_cond_t count_nonzero;
unsigned count = 0;

Dec()
{
    pthread_mutex_lock (&count_lock);
    while(count==0)
        pthread_cond_wait( &count_nonzero, &count_lock);   // label 1

    count=count -1;
    pthread_mutex_unlock (&count_lock);
}
 
Add()
{
    pthread_mutex_lock(&count_lock);
 
    if(count==0)
        pthread_cond_signal(&count_nonzero);                // label2
 
    count=count+1;
    pthread_mutex_unlock(&count_lock);                      // label3
}

Add2()
{
    if(count==0)
        pthread_cond_signal(&count_nonzero);                // label4
 
    count=count+1;
}

我们在线程A中执行Dec,在线程B中执行Add。
然后我们主线程中CreateThread( Dec ); 再CreateThread( Add );
上述代码情况下:
  • 首先我们执行A线程,调用Dec,此时 count==0,线程A会被阻塞到Label1处。
  • 然后我们主线程执行了B线程,调用了Add。
  • 然后Add调用label2处的signal,唤醒了线程A
  • 进行了线程切换,此时线程A被唤醒,但是A无法执行执行,因为它无法得到互斥锁count_lock。A被迫等待。
  • 此时B继续执行,B执行到label3之后, 释放了互斥锁。
  • A开始正常执行。
如果我们将代码Add中的互斥锁去除,而仅仅使用条件锁。则后果将会是
  • 首先我们执行A线程,调用Dec,此时 count==0,线程A会被阻塞到Label1处。
  • 然后我们主线程执行了B线程,调用了Add2。
  • 然后Add2调用label4处的signal,唤醒了线程A
  • 进行了线程切换,此时线程A被唤醒,但是A无法执行执行,因为count此时还为0,于是A被阻塞到了条件锁上。
  • 此时B继续执行,将count调整为1
  • 但是此时A卡在条件锁上,并没有新的解锁信号。A将永远无法被唤醒,出现了BUG。

伪代码
class ThreadMonitor
{
    struct ThreadMonitorImpl
    {
        pthread_mutex_t m_Mutex;
        pthread_cond_t m_Cond;
        int m_Value;
    };
    ThreadMonitor( int nValue ):m_pImpl( new ThreadMonitorImpl )
    {
        ((ThreadMonitorImpl*)m_Impl)->m_Value = nValue;
        pthread_mutex_init(&((ThreadMonitorImpl*)m_Impl)->m_Mutex, NULL);
        pthread_cond_init(&((ThreadMonitorImpl*)m_Impl)->m_Cond, NULL);        
    }
    ~ThreadMonitor()
    {
          pthread_cond_destroy(&((ThreadMonitorImpl*)m_Impl)->m_Cond);
          pthread_mutex_destroy(&((ThreadMonitorImpl*)m_Impl)->m_Mutex);
    }
    void Set( int nValue )                                        // 无条件设置该值
    {
          pthread_mutex_lock(&((ThreadMonitorImpl*)m_Impl)->m_Mutex);
          ((ThreadMonitorImpl*)m_Impl)->m_Value = value;
          pthread_cond_signal(&((ThreadMonitorImpl*)m_Impl)->m_Cond);
          pthread_mutex_unlock(&((ThreadMonitorImpl*)m_Impl)->m_Mutex);
    }
    void  Wait( int nWaitValue, int nSetValue )    // 阻塞等待线程监视器达到nWaitValue,并在达到后将监视器状态设置为新的值(当前你可以不修改改值,例如Wait(0,0))
    {
          Log("waiting for %d", nWaitValue);
          pthread_mutex_lock(&((ThreadMonitorImpl*)m_Impl)->m_Mutex);
          while (((ThreadMonitorImpl*)m_Impl)->m_Value != nWaitValue)            // 若值不符合,则死锁等待
          {
             pthread_cond_wait(&((ThreadMonitorImpl*)m_Impl)->m_Cond, &((ThreadMonitorImpl*)m_Impl)->m_Mutex);
          }
          ((ThreadMonitorImpl*)m_Impl)->m_Value = setValue;
          pthread_cond_signal(&((ThreadMonitorImpl*)m_Impl)->m_Cond);
          pthread_mutex_unlock(&((ThreadMonitorImpl*)m_Impl)->m_Mutex);
    }
    bool Poll( int nWantValue, int nSetValue )    // 单次查询线程监视器当前值是否达到nWaitValue,若达到则返回true并将监视器状态设置为新的值;若未达到,则返回false(当前你可以不修改改值,例如Poll(0,0))
    {
         bool success = false;
          pthread_mutex_lock(&((ThreadMonitorImpl*)m_Impl)->m_Mutex);
          if (nWantValue == ((ThreadMonitorImpl*)m_Impl)->m_Value)
          {
               ((ThreadMonitorImpl*)m_Impl)->m_Value = setValue;
               pthread_cond_signal(&((ThreadMonitorImpl*)m_Impl)->m_Cond);
               success = true;
          }
          pthread_mutex_unlock(&((ThreadMonitorImpl*)m_Impl)->m_Mutex);
          return success;
    }
    
    void* m_pImpl;
}
  评论这张
 
阅读(30)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017