zoukankan      html  css  js  c++  java
  • 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());
    }
    

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

  • 相关阅读:
    mysql设置用户密码规则
    jsonp格式前端发送和后台接受写法
    MySql数据库中正则表达式
    linux中服务(service)管理
    第50课 C++对象模型分析(上)
    第49课 多态的概念和意义
    第42课
    第41课
    深入理解MyBatis中的一级缓存与二级缓存
    hibernate一级缓存和二级缓存的区别
  • 原文地址:https://www.cnblogs.com/sigma0-/p/12630484.html
Copyright © 2011-2022 走看看