muduo网络库源码学习————条件变量

muduo里的CountDownLatch类实际上是对条件变量condition进行的封装,既可以用于所有子线程等待主线程发起 “起跑” ,也可以用于主线程等待子线程初始化完毕才开始工作。
condition.h代码如下:

// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//条件变量
#ifndef MUDUO_BASE_CONDITION_H
#define MUDUO_BASE_CONDITION_H

#include <muduo/base/Mutex.h>

#include <boost/noncopyable.hpp>
#include <pthread.h>

namespace muduo
{

class Condition : boost::noncopyable
{
 public:
    //构造函数只能显式调用
  explicit Condition(MutexLock& mutex) : mutex_(mutex)
  {//构造函数初始化条件变量
    pthread_cond_init(&pcond_, NULL);
  }
    //析构函数
  ~Condition()
  {//析构函数销毁条件变量
    pthread_cond_destroy(&pcond_);
  }
    //等待函数
  void wait()
  {
    pthread_cond_wait(&pcond_, mutex_.getPthreadMutex());
  }

  // returns true if time out, false otherwise.
  bool waitForSeconds(int seconds);
    //signal函数
  void notify()
  {
    pthread_cond_signal(&pcond_);
  }
    //broadcast函数
  void notifyAll()
  {
    pthread_cond_broadcast(&pcond_);
  }

 private:
  MutexLock& mutex_;//锁,不拥有他,是一个引用,不负责管理他的生存期
  pthread_cond_t pcond_;//为一个条件变量
};

}
#endif  // MUDUO_BASE_CONDITION_H

condition.cc

// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#include <muduo/base/Condition.h>

#include <errno.h>

// returns true if time out, false otherwise.
bool muduo::Condition::waitForSeconds(int seconds)
{
  struct timespec abstime;
  clock_gettime(CLOCK_REALTIME, &abstime);
  abstime.tv_sec += seconds;
  return ETIMEDOUT == pthread_cond_timedwait(&pcond_, mutex_.getPthreadMutex(), &abstime);
}

CountDownLatch.h

// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//对条件变量的封装,既可以用于所有子线程等待主线程发起起跑命令,
//也可以用于主线程等待子线程初始化完毕才开始工作
#ifndef MUDUO_BASE_COUNTDOWNLATCH_H
#define MUDUO_BASE_COUNTDOWNLATCH_H

#include <muduo/base/Condition.h>
#include <muduo/base/Mutex.h>

#include <boost/noncopyable.hpp>

namespace muduo
{

class CountDownLatch : boost::noncopyable
{
 public:
//构造函数,显示调用
  explicit CountDownLatch(int count);
//等待函数
  void wait();
//计数器减
  void countDown();
//获取当前计数器的值
  int getCount() const;

 private://mutable表明在const里可以改变他的状态
  mutable MutexLock mutex_;//互斥锁
  Condition condition_;//条件变量
  int count_;//计数器
};

}
#endif  // MUDUO_BASE_COUNTDOWNLATCH_H

CountDownLatch.cc

// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#include <muduo/base/CountDownLatch.h>

using namespace muduo;
//构造函数对值进行初始化,参数为计数器,构造mutex_对象,将mutex_对象传到condition_里面
CountDownLatch::CountDownLatch(int count): mutex_(), condition_(mutex_),count_(count)
{
}

void CountDownLatch::wait()
{
  MutexLockGuard lock(mutex_);
  //count_不为0则一直等待
  while (count_ > 0)
  {
    condition_.wait();
  }
}

void CountDownLatch::countDown()
{
  MutexLockGuard lock(mutex_);
  --count_;//count_减少
  if (count_ == 0) 
  {//如果count_为0,则通知所有的等待线程
    condition_.notifyAll();
  }
}

int CountDownLatch::getCount() const
{//得到count_的值
  MutexLockGuard lock(mutex_);
  return count_;
}

测试代码需要自己编写,如下所示,该程序先打印主进程id,建立3个线程,wait等待主线程发号施令,然后睡眠3秒,之后发起号令,打印各个线程的id,代码如下:

#include <muduo/base/CountDownLatch.h>
#include <muduo/base/Thread.h>

#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <string>
#include <stdio.h>
//测试程序
using namespace muduo;

class Test
{
 public:
  Test(int numThreads) : latch_(1),threads_(numThreads)
  {//CountDownLatch对象的计数值初始化为1,线程对象数组的容量初始化为传进来的参数
    for (int i = 0; i < numThreads; ++i)
    {//创建numThreads个线程
      char name[32];//线程的名称
      snprintf(name, sizeof name, "work thread %d", i);
      //创建线程,threadFunc为回调函数,因为是成员函数,所以要用&,this为当前类指针
      threads_.push_back(new muduo::Thread(boost::bind(&Test::threadFunc, this), muduo::string(name)));
    }
    //占位符为参数
    for_each(threads_.begin(), threads_.end(), boost::bind(&Thread::start, _1));
  }

  void run()
  {//count_初始化的时候赋为1,这里只需执行一次既可以跳出等待
    latch_.countDown();
  }

  void joinAll()
  {
    for_each(threads_.begin(), threads_.end(), boost::bind(&Thread::join, _1));
  }

 private:

  void threadFunc()
  {
    latch_.wait();//等待主线程发号施令
    printf("tid=%d, %s started
", CurrentThread::tid(), CurrentThread::name());

    printf("tid=%d, %s stopped
",CurrentThread::tid(),CurrentThread::name());
  }

  CountDownLatch latch_;//CountDownLatch对象
  boost::ptr_vector<Thread> threads_;//线程对象数组
};

int main()
{//首先打印当前进程pid,当前线程tid
  printf("pid=%d, tid=%d
", ::getpid(), CurrentThread::tid());
  //构造Test对象
  Test t(3);
  sleep(3);
  printf("pid=%d, tid=%d %s running ...
", ::getpid(), CurrentThread::tid(), CurrentThread::name());
  t.run();//发号施令
  t.joinAll();

  printf("number of created threads %d
", Thread::numCreated());
}

由于线程竞争,运行结果不唯一:
这里写图片描述
另一个结果:
这里写图片描述

原文地址:https://www.cnblogs.com/sigma0-/p/12630484.html