• 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线程池的更多相关文章

  1. 托管C++线程锁实现 c++11线程池

    托管C++线程锁实现   最近由于工作需要,开始写托管C++,由于C++11中的mutex,和future等类,托管C++不让调用(报错),所以自己实现了托管C++的线程锁. 该类可确保当一个线程位于 ...

  2. 简单的C++11线程池实现

    线程池的C++11简单实现,源代码来自Github上作者progschj,地址为:A simple C++11 Thread Pool implementation,具体博客可以参见Jakob's D ...

  3. c++11 线程池学习笔记 (一) 任务队列

    学习内容来自一下地址 http://www.cnblogs.com/qicosmos/p/4772486.html github https://github.com/qicosmos/cosmos ...

  4. C++11线程池的实现

    什么是线程池 处理大量并发任务,一个请求一个线程来处理请求任务,大量的线程创建和销毁将过多的消耗系统资源,还增加了线程上下文切换开销. 线程池通过在系统中预先创建一定数量的线程,当任务请求到来时从线程 ...

  5. c++11线程池实现

    咳咳.c++11 增加了线程库,从此告别了标准库不支持并发的历史. 然而 c++ 对于多线程的支持还是比較低级,略微高级一点的使用方法都须要自己去实现,譬如线程池.信号量等. 线程池(thread p ...

  6. 基于hystrix的线程池隔离

    hystrix进行资源隔离,其实是提供了一个抽象,叫做command,就是说,你如果要把对某一个依赖服务的所有调用请求,全部隔离在同一份资源池内 对这个依赖服务的所有调用请求,全部走这个资源池内的资源 ...

  7. 开源项目SMSS开发指南(二)——基于libevent的线程池

    libevent是一套轻量级的网络库,基于事件驱动开发.能够实现多线程的多路复用和注册事件响应.本文将介绍libevent的基本功能以及如何利用libevent开发一个线程池. 一. 使用指南 监听服 ...

  8. 基于linux与线程池实现文件管理

    项目要求 1.基本 用线程池实现一个大文件夹的拷贝,大文件夹嵌套很多小文件:实现复制到指定文件夹的全部文件夹. 2.扩充功能 显示进度条:拷贝耗时统计:类似linux的tree,不能直接用system ...

  9. c++ 11 线程池---完全使用c++ 11新特性

    前言: 目前网上的c++线程池资源多是使用老版本或者使用系统接口实现,使用c++ 11新特性的不多,最近研究了一下,实现一个简单版本,可实现任意任意参数函数的调用以及获得返回值. 0 前置知识 首先介 ...

随机推荐

  1. Extjs grid column里添加button等html标签,并增加点击事件

    Extjs里有个actioncolumn,但actioncolumn只能添加一系列button,不能既有字又有button 如何能在column里增加html标签,并给button添加事件呢? 1. ...

  2. atitit.无损传输二进制数据串传输网络

    atitit.无损传输二进制数据串传输网络 1. gbk的网络传输问题,为什么gbk不能使用来传输二进制数据 1 2. base64 2 3. iso-8859-1  (推荐) 2 4. utf-8  ...

  3. OpenGL缓冲区

    OpenGL缓冲区 颜色缓冲区 OpenGL时,先是在一个缓冲区中完毕渲染,然后再把渲染结果交换到屏幕上. 我们把这两个缓冲区称为前颜色缓冲区(屏幕)和后颜色缓冲区.在默认情况下,OpenGL命令是在 ...

  4. NSIS API 函数常用备份

    原文:NSIS API 函数常用备份 关闭程序: System::Call `user32::AnimateWindow(i$HWNDPARENT,i200,i${AW_BLEND}|${AW_HID ...

  5. 蜗牛—苍茫IT文章大学的路(十)

    昨晚,有个叫***培训机构鼓吹我们学校.起初我还以为是介绍这个游戏吧.谁知道.它原来是一个培训结构.去年我买的表啊 我知道这会不会去,我也浪费了时间审查.因为今天下午和晚上来测试啊.我没有审查,. 当 ...

  6. Pro Aspnet MVC 4读书笔记(5) - Essential Tools for MVC

    Listing 6-1. The Product Model Class using System; using System.Collections.Generic; using System.Li ...

  7. SpringMVC注释启用

    这篇文章是我学习的网络视频SpringMVC写的过程. 谢谢公布各位前辈的视频 以下评论SpringMVC几个关键步骤,注意事项启用: 首先需要加载配置文件(假设请使用自定义路径) <? xml ...

  8. ORA-12638: 无法检索身份证明 解决的方法

    the NTS option makes the Oracle client attempt to use your current Windows domain credentials to aut ...

  9. Putty是一个专业的SSH连接客户端

    http://www.putty.ws/PuTTY-LinuxVPS Putty是一个专业的SSH连接客户端,当然可以用来连接Linux操作系统的VPS.下文是Putty连接工具的使用方法与详细教程, ...

  10. Android发展的一个重要方面Makefile分析

    Android发展的一个重要方面Makefile分析 随着移动互联网的发展,移动开发也越来越吃香了.眼下最火的莫过于android.android是什么就不用说了,android自从开源以来,就受到非 ...