【muduo】base篇---ThreadPool

一、线程池简介

  线程池本质上也是生产者消费者问题:生产者线程向任务队列添加任务,消费者线程(在线程队列中)从任务队列取出任务去执行。

在这里插入图片描述

二、ThreadPool源码

#ifndef MUDUO_BASE_THREADPOOL_H
#define MUDUO_BASE_THREADPOOL_H

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

#include <deque>
#include <vector>

namespace muduo
{

class ThreadPool : noncopyable
{
 public:
  // 定义function类模板
  typedef std::function<void ()> Task;

  explicit ThreadPool(const string& nameArg = string("ThreadPool"));
  ~ThreadPool();

  // 设置线程池中线程的最大数目
  void setMaxQueueSize(int maxSize) { maxQueueSize_ = maxSize; }

  // 设置回调函数
  void setThreadInitCallback(const Task& cb) { threadInitCallback_ = cb; }

  // 启动和终止线程池
  void start(int numThreads);
  void stop();

  const string& name() const { return name_; }

  size_t queueSize() const;

  void run(Task f);

 private:
  bool isFull() const REQUIRES(mutex_); // 判断是否满
  void runInThread(); // 线程池的线程运行函数
  Task take(); // 取任务函数(返回类型是一个function)
  mutable MutexLock mutex_; // mutable表示在const函数也可以改变它
  Condition notEmpty_ GUARDED_BY(mutex_); //任务队列queue_不为空,说明可以向任务队列取任务了
  Condition notFull_ GUARDED_BY(mutex_); //任务队列queue_不满了,说明可以向任务队列添加任务
  string name_;
  Task threadInitCallback_; // 线程初始化回调函数
  std::vector<std::unique_ptr<muduo::Thread>> threads_; // 线程组
  std::deque<Task> queue_ GUARDED_BY(mutex_); // 任务队列
  size_t maxQueueSize_; // 最大任务数
  bool running_; // 线程池运行状态
};

}  // namespace muduo

#endif  // MUDUO_BASE_THREADPOOL_H
#include <muduo/base/ThreadPool.h>

#include <muduo/base/Exception.h>

#include <assert.h>
#include <stdio.h>

using namespace muduo;

ThreadPool::ThreadPool(const string& nameArg)
  : mutex_(),
    notEmpty_(mutex_), // 初始化的时候需要把condition和mutex关联起来
    notFull_(mutex_),
    name_(nameArg),
    maxQueueSize_(0),
    running_(false)
{
}

ThreadPool::~ThreadPool()
{
  if (running_)
  {
    stop();
  }
}

/******************************************************************** 
Description : 启动线程池。
*********************************************************************/
void ThreadPool::start(int numThreads)
{
  assert(threads_.empty());
  running_ = true;
  // 预留空间,避免多次自动增长
  threads_.reserve(numThreads);
  for (int i = 0; i < numThreads; ++i)
  {
    char id[32];
    snprintf(id, sizeof id, "%d", i+1);
    // 创建线程并存放线程指针,绑定的函数为runInThread
    threads_.emplace_back(new muduo::Thread(std::bind(&ThreadPool::runInThread, this), name_+id));
    // 启动线程,即runInThread函数执行
    threads_[i]->start();
  }
  // 如果线程池线程数为0,且设置了回调函数
  if (numThreads == 0 && threadInitCallback_) 
  {
    threadInitCallback_(); // 本线程自己执行init回调函数
  }
}

/******************************************************************** 
Description : 终止线程池。
*********************************************************************/
void ThreadPool::stop()
{
  {
    MutexLockGuard lock(mutex_);
    running_ = false;
    // 不管当前线程在执行什么任务,通知所有线程去notEmpty_.wait()处等待
    // 因为running_为false,所有线程不会再执行任何任务了。
    notEmpty_.notifyAll();
  }
  // 回收所有线程
  for (auto& thr : threads_)
  {
    thr->join();
  }
}

// 获取任务队列的大小
size_t ThreadPool::queueSize() const
{
  MutexLockGuard lock(mutex_);
  return queue_.size();
}

/******************************************************************** 
Description : 向任务队列中添加任务。
*********************************************************************/
void ThreadPool::run(Task task)
{
  if (threads_.empty())
  {
    task(); // 如果没有子线程,就在主线程中直接执行该task
  }
  else
  {
    MutexLockGuard lock(mutex_);
    while (isFull())
    {
      notFull_.wait(); // 等待任务队列不为满的条件
    }
    assert(!isFull());
    // 如果任务队列不满,则可以向任务队列中添加任务
    queue_.push_back(std::move(task));
    notEmpty_.notify(); // 唤醒等待任务队列不为空的线程来取任务
  }
}

/******************************************************************** 
Description : 向任务队列中取任务,take函数是每个线程都执行的。
*********************************************************************/
ThreadPool::Task ThreadPool::take()
{
  MutexLockGuard lock(mutex_);
  // 避免虚假唤醒
  // 如果任务队列为空,并且线程池处于运行态
  while (queue_.empty() && running_)  
  {
    notEmpty_.wait(); // 等待任务队列不为空的条件
  }
  Task task; // 定义任务变量,Task是一个函数类型
  if (!queue_.empty()) // 任务队列不为空
  {
    task = queue_.front(); // 取队列头获取一个任务并初始化task
    queue_.pop_front();
    if (maxQueueSize_ > 0)
    {
      // 取了一个任务之后,唤醒等待任务队列不为满的线程来添加任务
      notFull_.notify(); 
    }
  }
  return task;
}

// 判断任务队列是否满
bool ThreadPool::isFull() const
{
  mutex_.assertLocked();
  return maxQueueSize_ > 0 && queue_.size() >= maxQueueSize_;
}

/******************************************************************** 
Description : 取任务并执行。
*********************************************************************/
void ThreadPool::runInThread()
{
  try
  {
    if (threadInitCallback_)
    {
      threadInitCallback_();
    }
    while (running_) // 当线程池启动之后,就在while循环中不停地取任务执行
    {
      Task task(take()); // 取任务并初始化task,无任务会阻塞
      if (task) // 如果任务非空
      {
        task(); // 执行该任务
      }
    }
  }
  catch (const Exception& ex)
  {
    fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str());
    fprintf(stderr, "reason: %s\n", ex.what());
    fprintf(stderr, "stack trace: %s\n", ex.stackTrace());
    abort();
  }
  catch (const std::exception& ex)
  {
    fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str());
    fprintf(stderr, "reason: %s\n", ex.what());
    abort();
  }
  catch (...)
  {
    fprintf(stderr, "unknown exception caught in ThreadPool %s\n", name_.c_str());
    throw; // rethrow
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
muduo是一个基于Linux的C++网络库,它专注于高性能和可伸缩性。根据引用,muduo是在Linux操作系统上开发和编译的。因此,它不支持Windows操作系统。 muduo使用了一些Linux特定的系统调用和功能,如timerfd和eventfd,这些功能在Windows中是不可用的。另外,muduo使用了一些Linux特定的库和工具链,如g++编译器和CMake构建系统。 引用提到muduo适用于IA32(英特尔32位体系架构)、FreeBSD和Darwin操作系统,分别是基于Intel的32位架构、类UNIX操作系统和苹果的操作系统。Windows操作系统并不在这个列表中。 综上所述,由于muduo的特定设计和依赖于Linux操作系统的功能,Windows操作系统不支持muduo。如果你正在使用Windows系统,并且需要一个类似的网络库,你可以考虑其他适用于Windows的替代品,如Boost.Asio。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [muduo网络库:18---muduo简介之(muduo库的由来、编译安装、目录结构、代码结构、线程模型)](https://blog.csdn.net/qq_41453285/article/details/105104845)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [muduo木铎学习(一)](https://blog.csdn.net/qq_36616692/article/details/88142811)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~青萍之末~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值