基于C++11的线程池
- 1.封装的线程对象
class task : public std::tr1::enable_shared_from_this<task>
{
public:
task():exit_(false){}
task( const task & ) = delete;
~task(){}
task & operator =( const task &) = delete; void start();
void stop()
{
exit_ = true;
sync_.notify_one();
}
void set_job( const std::function<void()> & job, const std::string & file, int line)
{//提交任务
{
std::unique_lock<std::mutex> lock(mutex_);
job_ = job;
file_ = file;
line_ = line;
}
sync_.notify_one();//通知主线程有任务要运行....
}
void print_job(){
LOG(INFO)<<"sumbit from:"<<file_<<":"<<line_;
}
private: bool exit_;
std::mutex mutex_;
std::condition_variable sync_;
std::function< void()> job_; //线程运行的任务。线程随意时刻。最多仅仅能运行一个任务。
std::thread::id id_;
std::string file_;
int line_; };void task::start()
{
auto job_proxy = [this] (){ id_ = std::this_thread::get_id(); while( !exit_ )
{ std::unique_lock<std::mutex> lock(mutex_); if( job_ )
{//有任务了,须要运行任务了
try
{
job_(); //运行任务的代码
}catch( std::exception & e)
{ }catch(...)
{ }
job_ = std::function<void()>(); //释放任务绑定的资源,主要为闭包捕获的资源,特别是shared_ptr对象.
tasks->job_completed( shared_from_this() ); //任务运行完毕。通知线程池
}else{
//没有任务的时候,等待其它线程提交任务。。
sync_.wait(lock); }
}
}; std::thread t(job_proxy); //创建并启动与task管理的线程
t.detach(); //分离模式,thread对象销毁了,可是其创建的线程还活着。 。。
}
- 2.线程池管理对象
class task_pool
{
public:
task_pool(unsigned int pool_size = 128):max_size_(pool_size),stop_all_(true)
{ }
~task_pool()
{
}
void job_completed( const std::tr1::shared_ptr<task> & t)//回收task对象
{ std::lock_guard<std::mutex> lock(mutex_);
bool need_to_notify = idle_tasks_.empty() && (!wait_for_running_jobs_.empty());
busying_tasks_.erase(t);
idle_tasks_.push_back(t);
LOG(INFO)<<"after job_completed, current idle tasks size:"<< idle_tasks_.size()
<<" busying tasks size:"<<busying_tasks_.size()
<<" wait for running jobs size:"<<wait_for_running_jobs_.size();
if( !busying_tasks_.empty() ){
(*busying_tasks_.begin())->print_job();
}
if( need_to_notify )//任务太多了,之前空暇线程使用完了,有任务在等待运行。须要通知
{
sync_.notify_one();
}
};
//提交任务
void submit_job( const std::function<void()> & job, const std::string file, int line)
{
if( stop_all_ )
{
return;
}
std::lock_guard<std::mutex> lock(mutex_);
bool need_notify = wait_for_running_jobs_.empty();
wait_for_running_jobs_.push(std::make_tuple(job,file,line)); if( need_notify )//等待运行的任务为空时。须要通知,其它情况不须要通知.
{
sync_.notify_one();
} }
void execute_job()
{ while(true)
{
std::unique_lock<std::mutex> lock(mutex_);
while(!stop_all_ && wait_for_running_jobs_.empty() )
{
//等待其它线程提交任务
sync_.wait(lock);
} if( stop_all_ )
{
return;
}
while(!stop_all_ && idle_tasks_.empty())
{
//有任务要运行,可是没有空暇线程,等待其它任务运行完毕。 sync_.wait(lock);
}
if( stop_all_ )
{
return;
} //有任务,也有空暇线程了
auto t = get_task();
auto job =wait_for_running_jobs_.front();
wait_for_running_jobs_.pop();
//分发任务到task 线程.
t->set_job(std::get<0>(job), std::get<1>(job), std::get<2>(job));
}
}
void stop_all()
{ std::lock_guard<std::mutex> lock(mutex_);
stop_all_ = true;
for( auto t : idle_tasks_ )
{
t->stop();
}
idle_tasks_.clear();
for( auto t : busying_tasks_ )
{
t->stop();
}
while(!wait_for_running_jobs_.empty()){
wait_for_running_jobs_.pop();
} sync_.notify_one();
} void start()
{// 初始化启动线程池主线程
try
{
std::thread t( [this]{ execute_job();});
t.detach(); stop_all_ = false;
allocate_tasks(); }catch( std::exception & e )
{
LOG(FATAL) << "start tasks pool ... error"<<e.what();
}
}
protected:
std::tr1::shared_ptr<task> get_task()
{
//获取task对象
if( ! idle_tasks_.empty() )
{
auto t = *idle_tasks_.begin();
idle_tasks_.pop_front(); //从空暇队列移除
busying_tasks_.insert(t); //增加忙队列 return t;
} return std::tr1::shared_ptr<task>(); } void allocate_tasks() //初始化线程池
{
for( int i = 0 ; i < max_size_; i ++ )
{
std::tr1::shared_ptr<task> t( new task());
try{
t->start();
idle_tasks_.push_back(t);
}catch( std::exception & e)
{ //超过进程最大线程数限制时。会跑出异常。。 。
break;
}
}
}
private :
unsigned int max_size_;
std::list < std::tr1::shared_ptr<task> > idle_tasks_; //空暇任务队列
std::set < std::tr1::shared_ptr<task> > busying_tasks_;//正在运行任务的队列
std::queue< std::tuple< std::function<void()> , std::string, int > > wait_for_running_jobs_; //等待运行的任务
std::mutex mutex_;
std::condition_variable sync_;
bool stop_all_;
};
- usage
static task_pool * tasks = nullptr;
static std::once_flag init_flag;
static std::once_flag finit_flag; void run_job(const std::function<void()> & job , const std::string & file, int line )
{
if( tasks != nullptr)
tasks->submit_job(job, file,line); }
void task_pool_init( unsigned max_task_size)
{
std::call_once(init_flag,[max_task_size]{
tasks = new task_pool(max_task_size);
tasks->start();
});
}
void task_pool_finit()
{
std::call_once(finit_flag,[]{ tasks->stop_all();});
}
基于C++11的线程池的更多相关文章
- 基于C++11实现线程池的工作原理
目录 基于C++11实现线程池的工作原理. 简介 线程池的组成 1.线程池管理器 2.工作线程 3.任务接口, 4.任务队列 线程池工作的四种情况. 1.主程序当前没有任务要执行,线程池中的任务队列为 ...
- 基于C++11的线程池实现
1.线程池 1.1 线程池是什么? 一种线程管理方式. 1.2 为什么用线程池? 线程的创建和销毁都需要消耗系统开销,当线程数量过多,系统开销过大,就会影响缓存局部性和整体性能.而线程池能够在充分利用 ...
- 基于C++11的线程池,简洁且可以带任意多的参数
咳咳.C++11 加入了线程库,从此告别了标准库不支持并发的历史.然而 c++ 对于多线程的支持还是比较低级,稍微高级一点的用法都需要自己去实现,譬如线程池.信号量等.线程池(thread pool) ...
- 基于C++11的线程池(threadpool),简洁且可以带任意多的参数
咳咳.C++11 加入了线程库,从此告别了标准库不支持并发的历史.然而 c++ 对于多线程的支持还是比较低级,稍微高级一点的用法都需要自己去实现,譬如线程池.信号量等.线程池(thread pool) ...
- 基于C++11的数据库连接池实现
0.注意 该篇文章为了让大家尽快看到效果,代码放置比较靠前,看代码前务必看下第4部分的基础知识. 1.数据库连接池 1.1 是什么? 数据库连接池负责分配.管理和释放数据库连接,属于池化机制的一种,类 ...
- 基于ThreadPoolExecutor,自定义线程池简单实现
一.线程池作用 在上一篇随笔中有提到多线程具有同一时刻处理多个任务的特点,即并行工作,因此多线程的用途非常广泛,特别在性能优化上显得尤为重要.然而,多线程处理消耗的时间包括创建线程时间T1.工作时间T ...
- 11 java 线程池 实现原理
一 关键类的实现 1 ThreadPoolExecutor类 java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类,因此如果要透彻地了解Java中的 ...
- 11 java 线程池 使用实例
在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...
- 使用C++11封装线程池ThreadPool
读本文之前,请务必阅读: 使用C++11的function/bind组件封装Thread以及回调函数的使用 Linux组件封装(五)一个生产者消费者问题示例 线程池本质上是一个生产者消费者模型,所 ...
随机推荐
- geolocation h5
navigator. geolocation.getCurrentPosition() 触发浏览器弹窗询问用户同意访问地址.接收三个参数:成功回调函数,可选的失败回调,可选选项对象 成功回调函数接 ...
- 认识Java WEB应用
JavaWeb应用概念 在Sun的JavaServlet规范中,对Java Web应用作了这样定义:JAVA Web应用由一组Servlet.HTML页.类.以及其它可以被绑定的资源构造.它可以在各种 ...
- webapp通用选择器:iosselect
1,这个组件解决什么问题 在IOS系统中,safari浏览器的select标签默认展示样式和iOS-UIPickerView展示方式一致,形如下图: 这个选择器操作方便,样式优美.但是在安卓系统中展示 ...
- Linux常用命令100个用法
平时用linux时,我有一个习惯就是把遇到的,比较有用,并且容易忘的命令,放到一个文本文件中,没事的时候可以拿出来看看,这样可以加深映像,时间长了这些命令的用法基本上都能掌握了.以下是100个用法,有 ...
- MyBatis 一、二级缓存和自定义缓存
1.一级缓存 MyBatis 默认开启了一级缓存,一级缓存是在SqlSession 层面进行缓存的.即,同一个SqlSession ,多次调用同一个Mapper和同一个方法的同一个参数,只会进行一 ...
- 通过游戏认识 --- JQuery与原生JS的差异
前言 jQuery是一个快速.简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库( 或JavaScript框架).jQuery设计的宗旨是“write ...
- StackExchange.Redis学习笔记(三) 数据库及密码配置 GetServer函数
这一章主要写一些StackExchange.Redis的配置及不太经常用到的函数 数据库连接 下面是我的连接字符串,里面指定了地址,密码,及默认的数据库 Redis启动后默认会分成0-15个数据库,不 ...
- RabbitMQ和SpringBoot的简单整合列子
一 思路总结 1 主要用spring-boot-starter-amqp来整合RabbitMQ和SpringBoot 2 使用spring-boot-starter-test来进行单元测试 3编写配置 ...
- NodeJS寻常小毛病
在写关于NodeJS项目中常遇到的小错误 此时用到的服务器是phpstudy中的MySQL 1. First argument must be a string or Buffer 解决方法: ...
- iOS swift的xcworkspace多项目管理(架构思想)
iOS swift的xcworkspace多项目管理(架构思想) 技术说明: 今天在这里分享 swift下的 xcworkspace多项目管理(架构思想),能为我们在开发中带来哪些便捷?能为我们对整 ...