基于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组件封装(五)一个生产者消费者问题示例 线程池本质上是一个生产者消费者模型,所 ...
随机推荐
- js跨域问题解决方案
跨域:当协议.域名.端口号任何一个不相同时,叫称为跨域. HTML5 CORS(cross-origin-resource-sharing)跨域资源共享: 原理:当需要访问跨域的资源时,可以通 ...
- 《Linux命令行与shell脚本编程大全》 第四章
4.1 监测程序 1. ps 默认只显示运行在当前控制台下的属于当前用户的进程. 可以接很多选项,比如 -A表示所有进程 -e等. 2. ps -l 查看进程更多信息 UID:启动这些进程的用 ...
- Javascript实现简单跨域调用
什么是JSONP? 1.一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面.动态网页.web服务.WCF,只要是跨域请求,一律不准: 2.不过我们又发现,Web页面 ...
- Android 工程师
转发:https://zhuanlan.zhihu.com/p/30429725 这句话我真的憋了好久.Android 工程师只要关注我,我就能让你达到大师级水平,不是面试时的吹牛逼水平,不是自我欺骗 ...
- [ASP.NET Core 2.0 前方速报]Core 2.0.3 已经支持引用第三方程序集了
发现问题 在将 FineUIMvc(支持ASP.NET MVC 5.2.3)升级到 ASP.NET Core 2.0 的过程中,我们发现一个奇怪的现象: 通过项目引用 FineUICore 工程一切正 ...
- 移动端效果之LoadMore
写在前面 列表一直是展示数据的一个重要方式,在手机端的列表展示又和PC端展示不同,毕竟手机端主要靠滑.之前手机端之前一直使用的IScroll,但是IScroll本身其实有很多兼容性BUG,想改动一下需 ...
- js的call() ,apply() 两种方法的区别和用法,最白话文的解释,让枯燥滚粗!
百度了一圈calll()函数和apply()函数,感觉还是糊里糊涂 正好我前几天刚又重新翻了一遍 那本 600多页 的圣经书,我习惯时不时的去打下基础,只是为了用来装逼,给人讲解....(我是有多蛋疼 ...
- Logstash&Redis&Elasticsearch&Kibana
[搭建] 一个很好的提示,强调版本的一致性 http://www.cnblogs.com/yjf512/p/4194012.html http://michael.bouvy.net/blog/en/ ...
- Xilinx FPGA LVDS应用
最近项目需要用到差分信号传输,于是看了一下FPGA上差分信号的使用.Xilinx FPGA中,主要通过原语实现差分信号的收发:OBUFDS(差分输出BUF),IBUFDS(差分输入BUF). 注意在分 ...
- 《java.util.concurrent 包源码阅读》27 Phaser 第一部分
Phaser是JDK7新添加的线程同步辅助类,作用同CyclicBarrier,CountDownLatch类似,但是使用起来更加灵活: 1. Parties是动态的. 2. Phaser支持树状结构 ...