1.C++11中引入了lambada表达式,很好的支持异步编程

2.C++11中引入了std::thread,可以很方便的构建线程,更方便的可移植特性

3.C++11中引入了std::mutex,可以很方便的构建线程锁互斥访问,更方便的可移植特性

4.C++11中引入了std::condition_variable,可以不依赖于win32 api实现自己的消费者生产者模型

5.利用改进版本的shared_ptr,可以很好的解决多线程生命周期的棘手问题

 /************************************************************************/
/* */
/************************************************************************/ #ifndef __CARBON_THREAD_POOL_H
#define __CARBON_THREAD_POOL_H #include <vector>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
#include <string>
#include <sstream>
#include <deque> namespace CARBON { //************************************
// Method: Create
// Returns: std::shared_ptr
// Qualifier: 用于创建智能指针实例
// Parameter: args, 可变参数,接受任意个数的参数,传递给T的构造函数
//************************************
template<typename T, typename... ARG>
std::shared_ptr<T> Create(ARG&&... args)
{
struct TEnableShared : public T
{
TEnableShared(ARG&&... args)
: T(std::forward<ARG>(args)...)
{}
}; return std::make_shared<TEnableShared>(std::forward<ARG>(args)...);
} class ThreadPool : public std::enable_shared_from_this<ThreadPool>
{
protected:
ThreadPool()
: _stop(false)
{} virtual ~ThreadPool()
{
{
std::unique_lock<std::mutex> lock(_lock);
_stop = true;
}
_condition.notify_all();
for (std::thread &worker : _workers)
worker.join();
} public:
// initialize thread pool with number of threads
bool InitializePool(size_t threads)
{
if (!_workers.empty()) return true; for (size_t i = ; i < threads; ++i)
{
std::weak_ptr<ThreadPool> _wtp = this->shared_from_this();
auto th = [](std::weak_ptr<ThreadPool> wtp) {
for (;;)
{
std::function<void()> task; {
std::shared_ptr<ThreadPool> stp = wtp.lock();
if (!stp)
return; std::unique_lock<std::mutex> lock(stp->_lock);
auto shipment = [&] ()->bool { return stp->_stop || !stp->_tasks.empty(); };
stp->_condition.wait(lock, shipment);
if (stp->_stop)
return;
if (stp->_tasks.empty())
continue;
task = std::move(stp->_tasks.front()).task;
stp->_tasks.pop_front();
} task();
}
};
_workers.emplace_back(th, _wtp);
} return !_workers.empty();
} //************************************
// Method: EnqueueTask
// Returns: std::future, 值类型由functor f指定
// Qualifier: 可以借由返回的std::future获取结果,但是更建议在functor中做异步通知
// Parameter: taskid 用于接受任务的id描述
// Parameter: functor f, 函数对象,用于执行任务
// Parameter: args, 可变参数,接受任意个数的参数,传递给functor f
//************************************
template<class F, class... Args>
auto EnqueueTask(std::string& taskid, F&& f, Args&&... args)
->std::future<typename std::result_of<F(Args...)>::type>
{
if (_workers.empty())
throw std::runtime_error("ThreadPool not initialized yet"); using return_type = typename std::result_of<F(Args...)>::type; auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
); std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(_lock); // don't allow enqueueing after stopping the pool
if (_stop)
throw std::runtime_error("enqueue on stopped ThreadPool"); stThreadTask st;
std::stringstream ss;
ss << (void*)task.get();
ss >> taskid;
st.taskid = taskid;
st.task = [task]() { (*task)(); };
_tasks.push_back(st);
}
_condition.notify_one();
return res;
} //************************************
// Method: GetTasksSize
// Returns: size_t
// Qualifier: 获取等待任务队列的任务数,正在执行的任务已经弹出队列,所以不参与计算
//************************************
size_t GetTasksSize()
{
std::unique_lock<std::mutex> lock(_lock);
return _tasks.size();
} //************************************
// Method: RemoveTask
// Returns: bool, 找到任务并移除则返回true,否则返回false
// Qualifier: 正在执行的任务已经弹出任务队列,应该在其它地方通知任务退出
// Qualifier: 执行完成的任务已经弹出任务队列,无法移除不存在的任务
// Qualifier: 该接口只能移除处在等待中的任务
// Parameter: taskid是任务的唯一标示,由EnqueueTask返回
//************************************
bool RemoveTask(const std::string& taskid)
{
std::unique_lock<std::mutex> lock(_lock);
for (auto& t = _tasks.begin(); t != _tasks.end(); ++t)
{
if (taskid == t->taskid)
{
_tasks.erase(t);
return true;
}
} return false;
} private:
typedef struct stThreadTask
{
std::function<void()> task;
std::string taskid;
}stThreadTask; // need to keep track of threads so we can join them
std::vector< std::thread > _workers;
// the task queue
std::deque< stThreadTask > _tasks; // synchronization
std::mutex _lock;
std::condition_variable _condition;
bool _stop;
};
} #endif

使用enable_shared_from_this来确保内部线程访问指针时,不会因为指针失效造成的非法访问

weak_ptr很好的保证了ThreadPool的生命周期安全性和实效性

由于使用了share_from_this,将初始化代码整体拿出来放到InitializePool中实现

ThreadPool的构造函数和析构函数声明为protected,用于保证外部不要直接生成ThreadPool实例

应该使用Create函数来生成ThreadPool实例

测试代码如下:

 namespace {
std::condition_variable _exit_cv;
} void func(int n)
{
std::cout << "func with n " << n << std::endl;
} using CARBON::ThreadPool; std::string taskid;
std::shared_ptr<ThreadPool> stp = CARBON::Create<ThreadPool>();
std::weak_ptr<ThreadPool> _wtp = stp;
stp->InitializePool(); stp->EnqueueTask(taskid, [](std::function<void(int)> cbf, std::weak_ptr<ThreadPool> wtp) ->int {
std::cout << "task1\n"; for (int i = ; i < ; ++i) {
std::mutex mtx;
std::unique_lock<std::mutex> lck(mtx);
if(_exit_cv.wait_for(lck, std::chrono::milliseconds()) == std::cv_status::no_timeout)
break; if (cbf) cbf(i);
if (wtp.expired())
break;
} return ;
}, func, _wtp);

当需要中断线程执行时,应该在外部通知线程中的任务自行退出

例子中可以在主线程中这么做

    _exit_cv.notify_all();
_exit_cv用于模拟sleep操作
func用于模拟任务结果的异步通知,这里为了省事使用了函数指针,实际工作中应该使用functor来传递,以保证生命周期的有效性
比如std::bind和shared_ptr一起构造的functor对象

基于C++11实现的线程池的更多相关文章

  1. 基于无锁队列和c++11的高性能线程池

    基于无锁队列和c++11的高性能线程池线程使用c++11库和线程池之间的消息通讯使用一个简单的无锁消息队列适用于linux平台,gcc 4.6以上   标签: <无>   代码片段(6)[ ...

  2. [C++]C风格、C++风格和C++11特性的线程池

    线程池概念 假设完成一项任务需要的时间=创建线程时间T1+线程执行任务时间T2+销毁线程时间T3,如果T1+T3的时间远大于T2,通常就可以考虑采取线程池来提高服务器的性能 thread pool就是 ...

  3. C++11的简单线程池代码阅读

    这是一个简单的C++11实现的线程池,代码很简单. 原理就是管理一个任务队列和一个工作线程队列. 工作线程不断的从任务队列取任务,然后执行.如果没有任务就等待新任务的到来.添加新任务的时候先添加到任务 ...

  4. 第11章 Windows线程池(3)_私有的线程池

    11.3 私有的线程池 11.3.1 创建和销毁私有的线程池 (1)进程默认线程池 当调用CreateThreadpoolwork.CreateThreadpoolTimer.CreateThread ...

  5. 第11章 Windows线程池(1)_传统的Windows线程池

    第11章 Windows线程池 11.1 传统的Windows线程池及API (1)线程池中的几种底层线程 ①可变数量的长任务线程:WT_EXECUTELONGFUNCTION ②Timer线程:调用 ...

  6. Windows核心编程:第11章 Windows线程池

    Github https://github.com/gongluck/Windows-Core-Program.git //第11章 Windows线程池.cpp: 定义应用程序的入口点. // #i ...

  7. 基于队列queue实现的线程池

    本文通过文章同步功能推送至博客园,显示排版可能会有所错误,请见谅! 写在前文:在Python中给多进程提供了进程池类,对于线程,Python2并没有直接提供线程池类(Python3中提供了线程池功能) ...

  8. 第11章 Windows线程池(2)_Win2008及以上的新线程池

    11.2 Win2008以上的新线程池 (1)传统线程池的优缺点: ①传统Windows线程池调用简单,使用方便(有时只需调用一个API即可) ②这种简单也带来负面问题,如接口过于简单,无法更多去控制 ...

  9. 使用C++11 实现的线程池

    最近打算做一个服务器端程序,每来一个客户端请求新开一个线程进行处理.在网上查了一些资料后,准备使用线程池来做这个东西.使用C++11新的库处理想线程问题比以前简单了许多,在网上找到一份线程池的实现,h ...

随机推荐

  1. Template Method(模板方法)

    意图: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.TemplateMethod 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 适用性: 一次性实现一个算法的不变的部分, ...

  2. [原][osgearth]FAQ

    参考:http://docs.osgearth.org/en/latest/faq.html Common Usage How do I place a 3D model on the map? Th ...

  3. 基于Codis的Redis集群部署

    Codis是基于代理的高性能Redis集群方案,使用Go语言进行开发,现在在在豌豆荚及其它公司内已经广泛使用,当然也包括我们公司. Codis与常见的Redis集群方案对比. 在搭建的时候,个人觉得R ...

  4. vue 脚手架(二,项目依赖说明 package.json)

    本文以转移至本人的个人博客,请多多关注! 本文以转移至本人的个人博客,请多多关注! 本文以转移至本人的个人博客,请多多关注! 本文以转移至本人的个人博客,请多多关注! 继续上一篇, 上一篇讲了 vue ...

  5. JSP 语法

    JSP 语法 本小节将会简单地介绍一下JSP开发中的基础语法. 脚本程序 脚本程序可以包含任意量的Java语句.变量.方法或表达式,只要它们在脚本语言中是有效的. 脚本程序的语法格式: <% 代 ...

  6. supervisor进程管理工具

    Supervisor 一个python写的进程管理工具,用来启动.关闭.重启进程,可以同时控制多个进程. 安装: pip install supervisor 配置: 通过配置文件来满足自己的需求 配 ...

  7. HIVE之常用字符串函数

    可以参考: 博文 : https://www.iteblog.com/archives/1639.html

  8. linux-mint下搭建android,angularjs,rails,html5开发环境

    目录[-] 必备软件: 环境配置: [open-jdk-6.0] [android-sdk] [ant] [github] [node.js] [rvm](ruby-1.9.3 rails-4.0.0 ...

  9. IOS UI-标签(Label)的高级应用

    // // BWLabel.h // IOS_0119_label // // Created by ma c on 16/1/19. // Copyright © 2016年 博文科技. All r ...

  10. bzoj1075

    题意: 给你一个地图,问从x1,y1->x2,y2,要走的路最短,问 耗油和速度 题解: 首先把他们转到左下角->右上角 然后只能往上或往下 考虑到可能有小数 所以都乘上他们的公倍数 然后 ...