C++11的简单线程池代码阅读
这是一个简单的C++11实现的线程池,代码很简单。
原理就是管理一个任务队列和一个工作线程队列。
工作线程不断的从任务队列取任务,然后执行。如果没有任务就等待新任务的到来。添加新任务的时候先添加到任务队列,然后通知任意(条件变量notify_one)一个线程有新的任务来了。
源代码来自https://github.com/progschj/ThreadPool
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
// 线程池类
class ThreadPool {
public:
// 构造函数,传入线程数
ThreadPool(size_t threads);
// 入队任务(传入函数和函数的参数)
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>;
// 一个最简单的函数包装模板可以这样写(C++11)适用于任何函数(变参、成员都可以)
// template<class F, class... Args>
// auto enqueue(F&& f, Args&&... args) -> decltype(declval<F>()(declval<Args>()...))
// { return f(args...); }
// C++14更简单
// template<class F, class... Args>
// auto enqueue(F&& f, Args&&... args)
// { return f(args...); }
// 析构
~ThreadPool();
private:
// need to keep track of threads so we can join them
// 工作线程组
std::vector< std::thread > workers;
// 任务队列
std::queue< std::function<void()> > tasks;
// synchronization 异步
std::mutex queue_mutex; // 队列互斥锁
std::condition_variable condition; // 条件变量
bool stop; // 停止标志
};
// the constructor just launches some amount of workers
// 构造函数仅启动一些工作线程
inline ThreadPool::ThreadPool(size_t threads)
: stop(false)
{
for(size_t i = 0;i<threads;++i)
// 添加线程到工作线程组
workers.emplace_back( // 与push_back类型,但性能更好(与此类似的还有emplace/emlace_front)
[this]
{ // 线程内不断的从任务队列取任务执行
for(;;)
{
std::function<void()> task;
{
// 拿锁(独占所有权式)
std::unique_lock<std::mutex> lock(this->queue_mutex);
// 等待条件成立
this->condition.wait(lock,
[this]{ return this->stop || !this->tasks.empty(); });
// 执行条件变量等待的时候,已经拿到了锁(即lock已经拿到锁,没有阻塞)
// 这里将会unlock释放锁,其他线程可以继续拿锁,但此处任然阻塞,等待条件成立
// 一旦收到其他线程notify_*唤醒,则再次lock,然后进行条件判断
// 当[return this->stop || !this->tasks.empty()]的结果为false将阻塞
// 条件为true时候解除阻塞。此时lock依然为锁住状态
// 如果线程池停止或者任务队列为空,结束返回
if(this->stop && this->tasks.empty()){
return;
}
// 取得任务队首任务(注意此处的std::move)
task = std::move(this->tasks.front());
// 从队列移除
this->tasks.pop();
}
// 执行任务
task();
}
}
);
}
// add new work item to the pool
// 添加一个新的工作任务到线程池
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;
// 将任务函数和其参数绑定,构建一个packaged_task
auto task = std::make_shared< std::packaged_task<return_type()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
// 获取任务的future
std::future<return_type> res = task->get_future();
{
// 独占拿锁
std::unique_lock<std::mutex> lock(queue_mutex);
// don't allow enqueueing after stopping the pool
// 不允许入队到已经停止的线程池
if(stop){
throw std::runtime_error("enqueue on stopped ThreadPool");
}
// 将任务添加到任务队列
tasks.emplace([task](){ (*task)(); });
}
// 发送通知,唤醒某一个工作线程取执行任务
condition.notify_one();
return res;
}
// the destructor joins all threads
inline ThreadPool::~ThreadPool()
{
{
// 拿锁
std::unique_lock<std::mutex> lock(queue_mutex);
// 停止标志置true
stop = true;
}
// 通知所有工作线程,唤醒后因为stop为true了,所以都会结束
condition.notify_all();
// 等待所有工作线程结束
for(std::thread &worker: workers){
worker.join();
}
}
#endif
C++11的简单线程池代码阅读的更多相关文章
- 基于C++11的100行实现简单线程池
基于C++11的100行实现简单线程池 1 线程池原理 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小, ...
- 基于无锁队列和c++11的高性能线程池
基于无锁队列和c++11的高性能线程池线程使用c++11库和线程池之间的消息通讯使用一个简单的无锁消息队列适用于linux平台,gcc 4.6以上 标签: <无> 代码片段(6)[ ...
- Linux下简单线程池的实现
大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的.在传统的多线程服务器模型中是这样实现的:一旦有个服务请求到达,就创建一个新的服务 ...
- 第11章 Windows线程池(1)_传统的Windows线程池
第11章 Windows线程池 11.1 传统的Windows线程池及API (1)线程池中的几种底层线程 ①可变数量的长任务线程:WT_EXECUTELONGFUNCTION ②Timer线程:调用 ...
- Linux简单线程池实现(带源码)
这里给个线程池的实现代码,里面带有个应用小例子,方便学习使用,代码 GCC 编译可用.参照代码看下面介绍的线程池原理跟容易接受,百度云下载链接: http://pan.baidu.com/s/1i3z ...
- [C++]C风格、C++风格和C++11特性的线程池
线程池概念 假设完成一项任务需要的时间=创建线程时间T1+线程执行任务时间T2+销毁线程时间T3,如果T1+T3的时间远大于T2,通常就可以考虑采取线程池来提高服务器的性能 thread pool就是 ...
- 第11章 Windows线程池(3)_私有的线程池
11.3 私有的线程池 11.3.1 创建和销毁私有的线程池 (1)进程默认线程池 当调用CreateThreadpoolwork.CreateThreadpoolTimer.CreateThread ...
- win32线程池代码(WinApi/C++)
win32线程池代码(WinApi/C++) 健壮, 高效,易用,易于扩, 可用于任何C++编译器 //说明, 这段代码我用了很久, 我删除了自动调整规模的代码(因为他还不成熟)/********** ...
- Linux多线程实践(9) --简单线程池的设计与实现
线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...
随机推荐
- [LeetCode] Find Minimum in Rotated Sorted Array 寻找旋转有序数组的最小值
Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...
- python学习之路 第三天
1.set集合:去掉重复字段 set.difference()找出不同并创建一个新的集合,不改变原来集合: set.difference_update() 改变原来集合,剔除掉括号内容: set.di ...
- 常用SQL
1. CEILING 向上取整2. FLOOR 向下取整3. FORMATmysql> SELECT FORMAT(12332.123456, 4); -> '12,332.1235'my ...
- 【BZOJ 4579】【Usaco2016 Open】Closing the Farm
http://www.lydsy.com/JudgeOnline/problem.php?id=4579 把时间倒过来,只是加点,并查集维护连通块. #include<cstdio> #i ...
- [转]别再抱怨了,国内这么多优秀的Android资源你都知道吗?
因为一些大家都知道的原因,android很多官方出品的优秀开发资源在国内无法访问. 国内的同行们对此也做出了很多努力,有很多朋友通过各种手段把很多优秀的资源搬运到了国内,为国内android开发者提供 ...
- Codeforces 刷水记录
Codeforces-566F 题目大意:给出一个有序数列a,这个数列中每两个数,如果满足一个数能整除另一个数,则这两个数中间是有一条边的,现在有这样的图,求最大联通子图. 题解:并不需要把图搞出来, ...
- Sublime Text编辑器的12个技巧和诀窍
本文为您提供Sublime Text编辑器的12个技巧和诀窍,深入挖掘这个看似简洁的代码编辑器,背后所隐藏的实现各种高级功能的无限可能. 1) 选择 以下是一些Sublime Text选择文本的快捷键 ...
- spring-mvc注解(mvc:annotation-driver,JSON,配置详解)
一.DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter 的使用已经过时! spring 3.1 开始我们应该用 Reque ...
- 引入DecimalFormat类进行数字格式化操作
引入语句:import java.text.DecimalFormat; 首先创建DecimalFormat类对象,利用类对象调用Format()方法进行格式化操作.这里有两种方法:①.Decimal ...
- Input输入框输入银行卡号自动空格
input输入框是表格中用都最多的,像输入手机,密码,银行卡号的,很多对于输入银行卡号是没有处理的,比如这样~~ 看起来是不是一团乱麻,, 眼睛瞬间一片漆黑~ 如果是这样,会不会好很多呢~~ 其实逻 ...