muduo网络库源码学习————线程池实现
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网络库源码学习————线程池实现的更多相关文章
- muduo网络库源码学习————线程类
muduo库里面的线程类是使用基于对象的编程思想,源码目录为muduo/base,如下所示: 线程类头文件: // Use of this source code is governed by a B ...
- muduo网络库源码学习————线程特定数据
muduo库线程特定数据源码文件为ThreadLocal.h //线程本地存储 // Use of this source code is governed by a BSD-style licens ...
- muduo网络库源码学习————线程本地单例类封装
muduo库中线程本地单例类封装代码是ThreadLocalSingleton.h 如下所示: //线程本地单例类封装 // Use of this source code is governed b ...
- muduo网络库源码学习————线程安全
线程安全使用单例模式,保证了每次只创建单个对象,代码如下: Singleton.h // Use of this source code is governed by a BSD-style lice ...
- muduo网络库源码学习————Timestamp.cc
今天开始学习陈硕先生的muduo网络库,moduo网络库得到很多好评,陈硕先生自己也说核心代码不超过5000行,所以我觉得有必要拿过来好好学习下,学习的时候在源码上面添加一些自己的注释,方便日后理解, ...
- muduo网络库源码学习————日志滚动
muduo库里面的实现日志滚动有两种条件,一种是日志文件大小达到预设值,另一种是时间到达超过当天.滚动日志类的文件是LogFile.cc ,LogFile.h 代码如下: LogFile.cc #in ...
- muduo网络库源码学习————互斥锁
muduo源码的互斥锁源码位于muduo/base,Mutex.h,进行了两个类的封装,在实际的使用中更常使用MutexLockGuard类,因为该类可以在析构函数中自动解锁,避免了某些情况忘记解锁. ...
- muduo网络库源码学习————日志类封装
muduo库里面的日志使方法如下 这里定义了一个宏 #define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) ...
- muduo网络库源码学习————无界队列和有界队列
muduo库里实现了两个队列模板类:无界队列为BlockingQueue.h,有界队列为BoundedBlockingQueue.h,两个测试程序实现了生产者和消费者模型.(这里以无界队列为例,有界队 ...
随机推荐
- 最全的中文NLP资源库,你确定不来看一下吗?
最全的中文NLP资源库,你确定不来看一下吗? 22/100 发布文章 qq_39248703 hello,小伙伴们大家好,今天给大家分享NLP资源库,可以说是最全的资源库了,很多包非常有趣,值得收藏, ...
- git log查看某文件的修改历史
1. git log filename 可以看到fileName相关的commit记录 2. git log -p filename可以显示每次提交的diff 3. 只看某次提交中的某个文件变化,可以 ...
- 邮件退信“Remote Server returned '420 4.2.0 Recipient deferred because there is no Mdb'”
标题是一个近期遇到的NDR 对于Exchange运维工作者,NDR通常给了我们较为清晰的排错方向,我们先看一下退信的原因, 我的一台MailBox报错“远程服务器返回‘420 4.2.0’接受延迟,因 ...
- Linux中vim编辑器 的 快捷键 --- 常用 的 都比较全
Linux中vim编辑器的功能非常强大,许多常用快捷键用起来非常方便,这里将我学vim入门时学的一些常用的快捷键分享给大家一下,希望可以帮助你们. 这个是我将鸟哥书上的进行了一下整理的,希望不要涉及到 ...
- 数据结构和算法(Golang实现)(22)排序算法-希尔排序
希尔排序 1959 年一个叫Donald L. Shell (March 1, 1924 – November 2, 2015)的美国人在Communications of the ACM 国际计算机 ...
- 【翻译】Java Array的排名前十方法(Top 10 Methods for Java Arrays)
这里列举了Java Array 的前十的方法.他们在stackoverflow最大投票的问题. The following are top 10 methods for Java Array. The ...
- 【Java】关键字 和 保留字
Java的关键字[Keyword]和 保留字[Reserved word] 官方描述: https://docs.oracle.com/javase/tutorial/java/nutsandbolt ...
- Java读源码之CountDownLatch
前言 相信大家都挺熟悉 CountDownLatch 的,顾名思义就是一个栅栏,其主要作用是多线程环境下,让多个线程在栅栏门口等待,所有线程到齐后,栅栏打开程序继续执行. 案例 用一个最简单的案例引出 ...
- spring boot连接linux服务器上的redis
本文章为给新手学习spring boot远程连通redis提供一个学习参考. 环境是intellij idea(window)+ redis(linux虚拟机-vmware). 首先在linux安装好 ...
- bootstrop日历
https://blog.csdn.net/cuixiaobo521/article/details/77880633