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

来源:互联网 发布:反转故事知乎 编辑:程序博客网 时间:2024/05/22 20:28

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\n", CurrentThread::tid(), CurrentThread::name());    printf("tid=%d, %s stopped\n",CurrentThread::tid(),CurrentThread::name());  }  CountDownLatch latch_;//CountDownLatch对象  boost::ptr_vector<Thread> threads_;//线程对象数组};int main(){//首先打印当前进程pid,当前线程tid  printf("pid=%d, tid=%d\n", ::getpid(), CurrentThread::tid());  //构造Test对象  Test t(3);  sleep(3);  printf("pid=%d, tid=%d %s running ...\n", ::getpid(), CurrentThread::tid(), CurrentThread::name());  t.run();//发号施令  t.joinAll();  printf("number of created threads %d\n", Thread::numCreated());}

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

0 0