muduo库里面的线程池是固定线程池,即创建的线程池里面的线程个数是一定的,不是动态的。线程池里面一般要包含线程队列还有任务队列,外部程序将任务存放到线程池的任务队列中,线程池中的线程队列执行任务,也是一种生产者和消费者模型。muduo库中的线程池源码如下:

线程池头文件ThreadPool.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_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 <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/ptr_container/ptr_vector.hpp> #include <deque>
//固定线程池,创建的线程个数是一定的
namespace muduo
{ class ThreadPool : boost::noncopyable
{
public:
typedef boost::function<void ()> Task; explicit ThreadPool(const string& name = string());
~ThreadPool();
//启动线程池
void start(int numThreads);
//关闭线程池
void stop();
//运行任务,往线程池当中的任务队列添加任务
void run(const Task& f); private:
//线程池当中的线程要执行的函数
void runInThread();
//获取任务
Task take(); MutexLock mutex_;//和条件变量配合使用的互斥锁
Condition cond_;//条件变量用来唤醒线程池中的线程队列来执行任务
string name_;//线程池名称
boost::ptr_vector<muduo::Thread> threads_;//存放线程指针
std::deque<Task> queue_;//任务队列
bool running_;//线程池是否处于运行的状态
}; } #endif

线程池实现文件ThreadPool.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/ThreadPool.h> #include <muduo/base/Exception.h> #include <boost/bind.hpp>
#include <assert.h>
#include <stdio.h> using namespace muduo;
//构造函数参数为线程池的名称
ThreadPool::ThreadPool(const string& name) : mutex_(),cond_(mutex_), name_(name),running_(false)
{
} ThreadPool::~ThreadPool()
{
if (running_)
{//如果线程池处于运行状态,则停止线程池
stop();
}
}
//启动固定的线程池
void ThreadPool::start(int numThreads)
{
assert(threads_.empty());//断言当前线程池为空
running_ = true;//置线程池处于运行的状态
threads_.reserve(numThreads);//预留这么多个空间
for (int i = 0; i < numThreads; ++i)
{//for循环创建线程
char id[32];
//线程号
snprintf(id, sizeof id, "%d", i);
//创建线程并存放线程指针,绑定的函数为runInThread
threads_.push_back(new muduo::Thread(boost::bind(&ThreadPool::runInThread, this), name_+id));
threads_[i].start();//启动线程,即runInThread函数执行
}
}
//关闭线程池
void ThreadPool::stop()
{
{
MutexLockGuard lock(mutex_);
running_ = false;//running置为false
cond_.notifyAll();//通知所有线程
}
//等待线程退出
for_each(threads_.begin(),threads_.end(),boost::bind(&muduo::Thread::join, _1));
}
//添加任务
void ThreadPool::run(const Task& task)
{//将任务添加到线程池当中的任务队列
if (threads_.empty())//如果线程池当中的线程是空的
{
task();//直接执行任务
}
else//否则添加
{
MutexLockGuard lock(mutex_);
queue_.push_back(task);
cond_.notify();//通知队列当中有任务了
}
}
//获取任务函数
ThreadPool::Task ThreadPool::take()
{//加锁保护
MutexLockGuard lock(mutex_);
// always use a while-loop, due to spurious wakeup
//如果队列为空并且处于运行的状态
while (queue_.empty() && running_)
{
cond_.wait();//等待
}
Task task;//定义任务变量,Task是一个函数类型
if(!queue_.empty())//有任务到来
{
task = queue_.front();//取出任务
queue_.pop_front();//弹出任务
}
return task;//返回任务
} void ThreadPool::runInThread()
{
try//可能发生异常
{
while (running_)
{//获取任务
Task task(take());
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
}
}

下面是测试代码:

ThreadPool_test.cc

//线程池测试代码
#include <muduo/base/ThreadPool.h>
#include <muduo/base/CountDownLatch.h>
#include <muduo/base/CurrentThread.h> #include <boost/bind.hpp>
#include <stdio.h> void print()
{//简单地打印tid
printf("tid=%d\n", muduo::CurrentThread::tid());
} void printString(const std::string& str)
{
printf("tid=%d, str=%s\n", muduo::CurrentThread::tid(), str.c_str());
} int main()
{//创建一个线程池
muduo::ThreadPool pool("MainThreadPool");
//5个线程的线程池
pool.start(5);
//添加了2个任务运行print
pool.run(print);
pool.run(print);
//添加了100个任务
for (int i = 0; i < 100; ++i)
{
char buf[32];
snprintf(buf, sizeof buf, "task %d", i);
//绑定的函数是带参数的
pool.run(boost::bind(printString, std::string(buf)));
}
//创建CountDownLatch对象,计数值count =1,只需执行一个countDown
muduo::CountDownLatch latch(1);
//添加一个任务
pool.run(boost::bind(&muduo::CountDownLatch::countDown, &latch));
//count不为0的时候一直等待
latch.wait();
//关闭线程池
pool.stop();
}

执行结果如下:

muduo网络库源码学习————线程池实现的更多相关文章

  1. muduo网络库源码学习————线程类

    muduo库里面的线程类是使用基于对象的编程思想,源码目录为muduo/base,如下所示: 线程类头文件: // Use of this source code is governed by a B ...

  2. muduo网络库源码学习————线程特定数据

    muduo库线程特定数据源码文件为ThreadLocal.h //线程本地存储 // Use of this source code is governed by a BSD-style licens ...

  3. muduo网络库源码学习————线程本地单例类封装

    muduo库中线程本地单例类封装代码是ThreadLocalSingleton.h 如下所示: //线程本地单例类封装 // Use of this source code is governed b ...

  4. muduo网络库源码学习————线程安全

    线程安全使用单例模式,保证了每次只创建单个对象,代码如下: Singleton.h // Use of this source code is governed by a BSD-style lice ...

  5. muduo网络库源码学习————Timestamp.cc

    今天开始学习陈硕先生的muduo网络库,moduo网络库得到很多好评,陈硕先生自己也说核心代码不超过5000行,所以我觉得有必要拿过来好好学习下,学习的时候在源码上面添加一些自己的注释,方便日后理解, ...

  6. muduo网络库源码学习————日志滚动

    muduo库里面的实现日志滚动有两种条件,一种是日志文件大小达到预设值,另一种是时间到达超过当天.滚动日志类的文件是LogFile.cc ,LogFile.h 代码如下: LogFile.cc #in ...

  7. muduo网络库源码学习————互斥锁

    muduo源码的互斥锁源码位于muduo/base,Mutex.h,进行了两个类的封装,在实际的使用中更常使用MutexLockGuard类,因为该类可以在析构函数中自动解锁,避免了某些情况忘记解锁. ...

  8. muduo网络库源码学习————日志类封装

    muduo库里面的日志使方法如下 这里定义了一个宏 #define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) ...

  9. muduo网络库源码学习————无界队列和有界队列

    muduo库里实现了两个队列模板类:无界队列为BlockingQueue.h,有界队列为BoundedBlockingQueue.h,两个测试程序实现了生产者和消费者模型.(这里以无界队列为例,有界队 ...

随机推荐

  1. C++ memset函数用法

    #include<stdio.h>#include<string.h>int main(){ char buffer[] = "I love you!"; ...

  2. CVE-2019-0193 远程命令执行-漏洞复现

    0x01 漏洞简介 Apache Solr 是一个开源的搜索服务器.Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现.此次漏洞出现在Apache Solr的 ...

  3. vue的组件缓存(返回页面不刷新)

    每次使用返回是页面总是会刷新 导致了一些体验上的不愉快 现在 发现vue中的一个很方便的方法还可以用来优化性能就是: keep-alive缓存组件 <router-view v-if=" ...

  4. CVPR2020|3D-VID:基于LiDar Video信息的3D目标检测框架

    作者:蒋天园 Date:2020-04-18 来源:3D-VID:基于LiDar Video信息的3D目标检测框架|CVPR2020 Brief paper地址:https://arxiv.org/p ...

  5. Docker-CentOS系统安装Docker

    上一节,我们介绍了安装虚拟机及操作系统,本文再详细描述安装docker的命令. 前提条件 虚拟机系统:CentOS,并且虚拟机能连通外网. 另外,虚拟机最好配置上阿里的镜像源,点此链接,进入cento ...

  6. Python-元组tuple、列表list、字典dict

    1.元组tuple(1)元组是有序列表,有不可见的下标,下标从0开始(2)元组的数据是相对固定的,数据不能增删改,他的一个重要用途是保存固定的.安全要求高的数据(3)元组用小括号()括起来,空元组定义 ...

  7. java面试题(一年工作经验)的心得

    看面试题 正常人第一步肯定都会看面试题,我也不例外,在看的过程中,我发现有些文章写的不错,对我帮助不小值得推荐,如下: Java面试题全集(上) 很多基础的东西,建议先看. 各大公司Java后端开发面 ...

  8. jmeter if控制器使用

    if控制器有两种用法 1.不勾选“interpret condition as variable expression” 直接输入我们需要判断的表达式即可,判断表达式为真时,执行if控制器下的请求 2 ...

  9. PHP反序列化漏洞总结(二)

    写在前边 之前介绍了什么是序列化和反序列化,顺便演示了一个简单的反序列化漏洞,现在结合实战,开始填坑 前篇:https://www.cnblogs.com/Lee-404/p/12771032.htm ...

  10. jQuery的attr和prop属性

    <div id="div1"></div> attr: 首先是一个参数的attr. $("#div").attr("id&qu ...