浅析muduo库中的线程设施01

muduo是目前在学习过程中遇到的最具有学习意义的网络库,下文将分析muduo库中的基础设施–Thread和ThreadPool.文中观点如果部分不符合您的理解,请留言指教,谢谢~
首先,介绍在多线程编程中不可缺少的同步措施–Mutex和Condition.

  • Mutex
class MutexLock : boost::noncopyable
{
 public:
  MutexLock()//创建一个mutex
    : holder_(0)
  {
    MCHECK(pthread_mutex_init(&mutex_, NULL));//MCHECK是muduo提供的宏定义检验函数
  }

  ~MutexLock()
  {
    assert(holder_ == 0);
    MCHECK(pthread_mutex_destroy(&mutex_));//销毁mutex
  }

  // must be called when locked, i.e. for assertion
  bool isLockedByThisThread() const//是否被当前线程锁住
  {
    return holder_ == CurrentThread::tid();//防止跨线程调用
  }

  void assertLocked() const
  {
    assert(isLockedByThisThread());
  }

  // internal usage

  void lock()
  {
    MCHECK(pthread_mutex_lock(&mutex_));//加锁
    assignHolder();//加锁时获得当前线程的线程号,即当前线程拥有这个锁
  }

  void unlock()
  {
    unassignHolder();//表示目前没有线程拥有这个锁
    MCHECK(pthread_mutex_unlock(&mutex_));//去锁
  }

  pthread_mutex_t* getPthreadMutex() /* non-const */
  {
    return &mutex_;
  }

 private:
  friend class Condition;//条件变量必须持有了锁之后才能使用

  class UnassignGuard : boost::noncopyable//防止条件变量在占有这个锁的时候,锁被销毁;将holder_设置为0,则既不能被其他线程调用也不能被当前线程销毁
  {
   public:
    UnassignGuard(MutexLock& owner)
      : owner_(owner)
    {
      owner_.unassignHolder();
    }

    ~UnassignGuard()//表示锁被释放
    {
      owner_.assignHolder();
    }

   private:
    MutexLock& owner_;
  };

  void unassignHolder()
  {
    holder_ = 0;
  }

  void assignHolder()
  {
    holder_ = CurrentThread::tid();
  }

  pthread_mutex_t mutex_;
  pid_t holder_;
};
 }
//该类负责管理互斥量的加锁和解锁
class MutexLockGuard : boost::noncopyable
{   
 public:
  explicit MutexLockGuard(MutexLock& mutex)
    : mutex_(mutex)//加锁
  {
    mutex_.lock();
  }

  ~MutexLockGuard()
  {
    mutex_.unlock();
  }

 private:

  MutexLock& mutex_;
};

有四种操作互斥锁的方式:创建,销毁,加锁,解锁。在muduo中,用一个低级的资源管理类MutexLock来实现这四种操作,再用一个较高级的资源管理类MutexLockGuard来管理MutexLock,即用RAII手法对资源进行两次封装,防止资源泄漏。

两个类都具有nocopy的属性,试想对Mutex的拷贝会在多线程程序中造成什么样的结果?有至少两个线程在同一时间拥有对一份资源的使用资格,后果不可设想。

在MutexLock中有一个好玩的私有变量:holder_. 该变量在一个线程对资源加锁时,将holder_设置为使用资源线程的索引;解锁时将holder_设置为0。初始化Mutex时将holder_设置为0;销毁时检查holder_是否为0。以上四个步骤保证了Mutex在某一个时间段内能被一个线程使用。

MutexLock与Condition是友元关系,具有很强的耦合度。

  • Condition
class Condition : boost::noncopyable
{//等待时需要占有互斥量,发送信号时不需要占有互斥量
 public:
  explicit Condition(MutexLock& mutex)
    : mutex_(mutex)
  {
    MCHECK(pthread_cond_init(&pcond_, NULL));
  }//不抛出异常的构造那函数,以及初始化条件变量

  ~Condition()//销毁条件变量
  {
    MCHECK(pthread_cond_destroy(&pcond_));
  }

  void wait()//使用之前需要占有互斥量
  {
    MutexLock::UnassignGuard ug(mutex_);//目前条件变量所在关联的Mutex不被当前线程所持有
    MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex()));
  }

  // returns true if time out, false otherwise.
  bool waitForSeconds(double seconds);//等待一定时间的wait

  void notify()
  {
    MCHECK(pthread_cond_signal(&pcond_));//通知一条线程
  }

  void notifyAll()//通知所有的线程
  {
    MCHECK(pthread_cond_broadcast(&pcond_));
  }

 private:
  MutexLock& mutex_;
  pthread_cond_t pcond_;
};

条件变量有五种操作方式:创建,销毁,等待,单一通知,全部通知。

在MutexLock中有一个内部类:UnassignGuard,该类的实例对象在Condition等待时创建,将holder_设置为0;当等待事件结束,又将holder_设置为原值。用MutexLock的析构函数检查等待事件是否发生在同一个线程中。目的是为了互斥量被意外的销毁。

Condition类中有一个waitForSecond函数,用于实现pthread_cond_timewait的封装。

条件变量在等待时需要持有互斥锁,但是在通知的时候不需要持有锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值