C++11下的线程池以及灵活的functional + bind + lamda
利用boost的thread实现一个线程类,维护一个任务队列,以便可以承载非常灵活的调用。这个线程类可以方便的为后面的线程池打好基础。线程池还是动态均衡,没有什么别的。由于minGW 4.7 对 C++11 thread 不支持,所以采用 boost 代替,linux 下是支持的,只是名字空间不同而已,套路都一样。先上代码: [cpp] view plaincopy #include #include <boost/thread/thread.hpp> #include <boost/thread/mutex.hpp> #include #include #include #include #include #include #include #include //This class defines a class contains a thread, a task queue class cpp11_thread { public: cpp11_thread() :m_b_is_finish(false) ,m_pthread(nullptr) { } ~cpp11_thread() { if (m_pthread != nullptr) delete m_pthread; m_list_tasks.clear(); } public: //wait until this thread is terminated; void join() { terminate(); if (m_pthread!=nullptr) m_pthread->join(); } //wait until this thread has no tasks pending. void wait_for_idle() { while(load()) boost::this_thread::sleep(boost::posix_time::milliseconds(200)); } //set the mask to termminiate void terminate() {m_b_is_finish = true; m_cond_incoming_task.notify_one();} //return the current load of this thread size_t load() { size_t sz = 0; m_list_tasks_mutex.lock(); sz = m_list_tasks.size(); m_list_tasks_mutex.unlock(); return sz; } //Append a task to do size_t append(std::function< void (void) > func) { if (m_pthread==nullptr) m_pthread = new boost::thread(std::bind(&cpp11_thread::run,this)); size_t sz = 0; m_list_tasks_mutex.lock(); m_list_tasks.push_back(func); sz = m_list_tasks.size(); //if there were no tasks before, we should notidy the thread to do next job. if (sz==1) m_cond_incoming_task.notify_one(); m_list_tasks_mutex.unlock(); return sz; } protected: std::atomic< bool> m_b_is_finish; //atomic bool var to mark the thread the next loop will be terminated. std::list<std::function< void (void)> > m_list_tasks; //The Task List contains function objects boost::mutex m_list_tasks_mutex; //The mutex with which we protect task list boost::thread *m_pthread; //inside the thread, a task queue will be maintained. boost::mutex m_cond_mutex; //condition mutex used by m_cond_locker boost::condition_variable m_cond_incoming_task; //condition var with which we notify the thread for incoming tasks protected: void run() { // loop wait while (!m_b_is_finish) { std::function< void (void)> curr_task ; bool bHasTasks = false; m_list_tasks_mutex.lock(); if (m_list_tasks.empty()==false) { bHasTasks = true; curr_task = *m_list_tasks.begin(); } m_list_tasks_mutex.unlock(); //doing task if (bHasTasks) { curr_task(); m_list_tasks_mutex.lock(); m_list_tasks.pop_front(); m_list_tasks_mutex.unlock(); } if (!load()) { boost::unique_lock< boost::mutex> m_cond_locker(m_cond_mutex); boost::system_time const timeout=boost::get_system_time()+ boost::posix_time::milliseconds(5000); if (m_cond_locker.mutex()) m_cond_incoming_task.timed_wait(m_cond_locker,timeout);//m_cond_incoming_task.wait(m_cond_locker); } } } }; //the thread pool class class cpp11_thread_pool { public: cpp11_thread_pool(int nThreads) :m_n_threads(nThreads) { assert(nThreads>0 && nThreads<=512); for (int i = 0; i< nThreads ;i++) m_vec_threads.push_back(std::shared_ptr<cpp11_thread>(new cpp11_thread())); } ~cpp11_thread_pool() { } public: //total threads; size_t count(){return m_vec_threads.size();} //wait until all threads is terminated; void join() { for_each(m_vec_threads.begin(),m_vec_threads.end(),[this](std::shared_ptr<cpp11_thread> & item) { item->terminate(); item->join(); }); } //wait until this thread has no tasks pending. void wait_for_idle() { int n_tasks = 0; do { if (n_tasks) boost::this_thread::sleep(boost::posix_time::milliseconds(200)); n_tasks = 0; for_each(m_vec_threads.begin(),m_vec_threads.end(),[this,&n_tasks](std::shared_ptr<cpp11_thread> & item) { n_tasks += item->load(); }); }while (n_tasks); } //set the mask to termminiate void terminate() { for_each(m_vec_threads.begin(),m_vec_threads.end(),[this](std::shared_ptr<cpp11_thread> & item) { item->terminate(); }); } //return the current load of this thread size_t load(int n) { return (n>=m_vec_threads.size())?0:m_vec_threads[n]->load(); } //Append a task to do void append(std::function< void (void) > func) { int nIdx = -1; unsigned int nMinLoad = -1; for (unsigned int i=0;i<m_n_threads;i++) { if (nMinLoad> m_vec_threads[i]->load()) { nMinLoad = m_vec_threads[i]->load(); nIdx = i; } } assert(nIdx>=0 && nIdx<m_n_threads); m_vec_threads[nIdx]->append(func); } protected: //NO. threads int m_n_threads; //vector contains all the threads std::vector<std::shared_ptr<cpp11_thread> > m_vec_threads; }; //a function which will be executed in sub thread. void hello() { //sleep for a while boost::this_thread::sleep(boost::posix_time::milliseconds(rand()%900+100)); std::cout << "Hello world, I'm a function runing in a thread!" << std::endl; } //a class has a method, which will be called in a thread different from the main thread. class A { private: int m_n; public: A(int n) :m_n(n) {} ~A(){} public: void foo (int k) { //sleep for a while boost::this_thread::sleep(boost::posix_time::milliseconds(rand()%900+100)); std::cout <<"n*k = "<<k*m_n<<std::endl; m_n++; } }; //let's test the thread. int main() { cpp11_thread_pool thread(2); srand((unsigned int)time(0)); A a(1),b(2),c(3); int nsleep = rand()%900+100; //append a simple function task thread.append(&hello); //append lamda thread.append ( [&nsleep]() { boost::this_thread::sleep(boost::posix_time::milliseconds(nsleep)); std::cout<<"I'm a lamda runing in a thread"<<std::endl; } ); //append object method with copy-constructor(value-assignment) thread.append(std::bind(&A::foo,a,10)); thread.append(std::bind(&A::foo,b,11)); thread.append(std::bind(&A::foo,c,12)); thread.append(std::bind(&A::foo,a,100)); //append object method with address assignment, will cause the objects' member increase. thread.append(std::bind(&A::foo,&a,10)); thread.append(std::bind(&A::foo,&b,11)); thread.append(std::bind(&A::foo,&c,12)); thread.append(std::bind(&A::foo,&a,100)); //wait for all tasks done. thread.wait_for_idle(); //kill thread.terminate(); //wait for killed thread.join(); //test function std::function < void (void) > func1 = &hello; std::function < void (void) > func2 = &hello; if (func1.target()!=func2.target()) return 0; else return 1; } 程序输出: [plain] view plaincopy Hello world, I'm a function runing in a thread! I'm a lamda runing in a thread n*k = 22 n*k = 10 n*k = 36 n*k = 100 n*k = 22 n*k = 10 n*k = 36 n*k = 200 Process returned 0 (0x0) execution time : 2.891 s Press any key to continue. 下面来看看代码。首先是线程类。 第13-99行是线程类。该类实现了一个带任务队列的线程模型。关键部件是62行的std::list<std::function< void (void)> > m_list_tasks; ,这个fifo 用来承载顺序在子线程运行的任务。任务通过48行的append方法进行追加,64行m_list_tasks_mutex是一个mutex,来保护队列的进出。65行定义的线程对象boost::thread在构造函数中初始化并运行,绑定了本对象的run方法。线程得以运行的关键是run方法,在71-99行定义。该方法首先判断是否有pending的任务,有的话就弹出来执行。如果任务做完了,则使用67行定义的条件变量m_cond_incoming_task 进行wait, 直到新的任务到来,在第56行触发条件,激活队列。 线程类还提供了一些方法,比如load()返回队列的大小,以及terminate终止线程。而后,转到线程池。线程池采用最简单的策略,即直接分配给最空闲的线程。 有了上述封装,main函数就简单多了。可以append几乎所有的东西到线程池,这是以前简单的利用 virtual function 很难做到的。
C++11下的线程池以及灵活的functional + bind + lamda的更多相关文章
- 第11章 Windows线程池(3)_私有的线程池
11.3 私有的线程池 11.3.1 创建和销毁私有的线程池 (1)进程默认线程池 当调用CreateThreadpoolwork.CreateThreadpoolTimer.CreateThread ...
- 第11章 Windows线程池(1)_传统的Windows线程池
第11章 Windows线程池 11.1 传统的Windows线程池及API (1)线程池中的几种底层线程 ①可变数量的长任务线程:WT_EXECUTELONGFUNCTION ②Timer线程:调用 ...
- [C++]C风格、C++风格和C++11特性的线程池
线程池概念 假设完成一项任务需要的时间=创建线程时间T1+线程执行任务时间T2+销毁线程时间T3,如果T1+T3的时间远大于T2,通常就可以考虑采取线程池来提高服务器的性能 thread pool就是 ...
- C++11的简单线程池代码阅读
这是一个简单的C++11实现的线程池,代码很简单. 原理就是管理一个任务队列和一个工作线程队列. 工作线程不断的从任务队列取任务,然后执行.如果没有任务就等待新任务的到来.添加新任务的时候先添加到任务 ...
- 基于无锁队列和c++11的高性能线程池
基于无锁队列和c++11的高性能线程池线程使用c++11库和线程池之间的消息通讯使用一个简单的无锁消息队列适用于linux平台,gcc 4.6以上 标签: <无> 代码片段(6)[ ...
- Windows核心编程:第11章 Windows线程池
Github https://github.com/gongluck/Windows-Core-Program.git //第11章 Windows线程池.cpp: 定义应用程序的入口点. // #i ...
- 使用C++11 实现的线程池
最近打算做一个服务器端程序,每来一个客户端请求新开一个线程进行处理.在网上查了一些资料后,准备使用线程池来做这个东西.使用C++11新的库处理想线程问题比以前简单了许多,在网上找到一份线程池的实现,h ...
- Linux下简单线程池的实现
大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的.在传统的多线程服务器模型中是这样实现的:一旦有个服务请求到达,就创建一个新的服务 ...
- Java并发(11)- 有关线程池的10个问题
引言 在日常开发中,线程池是使用非常频繁的一种技术,无论是服务端多线程接收用户请求,还是客户端多线程处理数据,都会用到线程池技术,那么全面的了解线程池的使用.背后的实现原理以及合理的优化线程池的大小等 ...
随机推荐
- 【录音】Android录音--AudioRecord、MediaRecorder
Android提供了两个API用于实现录音功能:android.media.AudioRecord.android.media.MediaRecorder. 网上有很多谈论这两个类的资料.现在大致总结 ...
- DataGrid( 数据表格) 组件[3]
本节课重点了解 EasyUI 中 DataGrid(数据表格)组件的使用方法,这个组件依赖于Panel(面板).Resizeable(调整大小).LinkButton(按钮).Pageination( ...
- Lesson 1: What is design? Why is it important?
Week 2: What is design? Why is it important? Article 1: Startups, this is how design works. It's a s ...
- ORA-01172 ORA-01151
今天发现服务器的9号硬盘坏了,因做了RAID5,报障后也没理会,过了一会儿,有人反应说报表运行不出来,发现服务器所有的硬盘都不工作了,界面也没有反应,就强行关机,再开机可以进入系统,等维修人员来换了新 ...
- Linux_x64安装Oracle11g(完整版)
一.修改操作系统核心参数 在Root用户下执行以下步骤: 1)修改用户的SHELL的限制,修改/etc/security/limits.conf文件 输入命令:vi /etc/security/lim ...
- scala学习笔记-集合
变长数组:数组缓冲 Scala中对于那种长度会变的数组的数据结构为ArrayBuffer. import scala.collection.mutable.ArrayBuffer; // 一个空的数组 ...
- [BZOJ]3643 Phi的反函数
我承认开这篇文章只是因为好笑…… 估计Zky神看见3737会很郁闷吧. http://www.lydsy.com/JudgeOnline/problem.php?id=3643 本来想直接交3737改 ...
- 关于js中的事件
这是第一篇技术性博客. 因为最近做的web版前端求职简历算是告一段落了(点此看简历).(稍微记录下吧:自从确定简历的简笔画风格后(因为刚开始设想的蓝天白云大树啥的不仅图片特难找而且做着做着就觉得有点俗 ...
- (翻译玩)SQLALchemy backref章节文档
Linking Relationships with Backref 自从在Object Relational Tutorial中第一次提到backref参数后,许多案例中也用到了backref,那么 ...
- c语言,全局变量,局部变量,外部函数,内部函数,stasic和extern的复习总结
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...