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. HDU - 4804 Campus Design 轮廓线dp

    题意:一个nm的矩阵被12的骨牌和11的骨牌完全覆盖,11的骨牌只能放c-d次,矩阵中有障碍物 题解:dp[i][j][k]表示到了第i行,第j个状态,放过k个11的骨牌,当前位有障碍物时只有一种转移 ...

  2. redis.conf配置文件参数说明

    参数说明 redis.conf 配置项说明如下: 1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程     daemonize no 2. 当Redis以守护 ...

  3. iis6手工创建网站后无法运行php脚本

    给人搬了十几个网站,老站用西部数码建站助手创建的,现在过期了无法继续创建,只能在Internet 信息服务(IIS)管理器创建网站,创建下来都没问题,但是就是无法打开网站. 测试打开txt文档.静态页 ...

  4. iOS开发Objective-C基础之──多态

    Objective-C语言是面向对象的高级编程语言,因此,它具有面向对象编程所具有的一些特性,即:封装性.继承性和多态性. 今天介绍一下Objective-C中的多态性. 一.什么是多态 多态:不同对 ...

  5. Beta阶段第2周/共2周 Scrum立会报告+燃尽图 08

    作业要求[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2389] 版本控制:https://git.coding.net/liuyy08 ...

  6. php session目录找不到的错误 Error session_start(): open(/var/lib/php/session error

    问题来源 今天安装一个应用,发现提示 Error session_start(): open(/var/lib/php/session error,估计是找不到写不了啥啥啥. 于是我就去该路径下去看看 ...

  7. Scss开发临时学习过程||webpack、npm、gulp配置

    SCSS语法: 假设变量申明带有!default,那么如果在此申明之前没有这个变量的申明,则用这个值,反之如果之前有申明,则用申明的值. ‘...’传递多个参数: @mixin box-shadow( ...

  8. Idea 使用 Maven 搭建 Web 项目

    传送门: 袁咩咩的小小博客 Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具. 使用它来搭建项目可以省去很多操作,它不仅有依赖管理.自动生成项目站 ...

  9. flask第二十二篇——模板【4】过滤器

    请关注微信公众号:自动化测试实战 先来教大家一个pycharm设置默认模板的方法.我们每次新建模板或者平时写代码打开以后可能都要重复写# coding: utf-8这些代码,其实我们可以设置好模板,让 ...

  10. Python面试题(十三)

    1.用最简洁的方式初始化这样一个变量:foo = [4,16,36,64,100] [i*i for i in range(2,12,2)] 答案 2.使用生成器编写fib函数,函数声明为fib(ma ...