分享一个C++11写的线程池
来源:互联网 发布:上海瀚威酩轩 知乎 编辑:程序博客网 时间:2024/06/10 08:11
上一篇博客讲述了一些线程池的知识。
但是C++11让线程变得更加简单,关于C++11线程方面的知识之前也有过介绍。
今天就介绍一个使用C++11写的简单的一个线程池,thread pool.
github地址:
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); template<class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>; ~ThreadPool();private: // need to keep track of threads so we can join them std::vector< std::thread > workers; // the task queue std::queue< std::function<void()> > tasks; // synchronization std::mutex queue_mutex; std::condition_variable condition; bool stop;};// the constructor just launches some amount of workersinline ThreadPool::ThreadPool(size_t threads) : stop(false){ for(size_t i = 0;i<threads;++i) workers.emplace_back( [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(); }); if(this->stop && this->tasks.empty()) return; task = std::move(this->tasks.front()); this->tasks.pop(); } task(); } } );}// add new work item to the pooltemplate<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; 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(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 threadsinline ThreadPool::~ThreadPool(){ { std::unique_lock<std::mutex> lock(queue_mutex); stop = true; } condition.notify_all(); for(std::thread &worker: workers) worker.join();}#endif
下面是简单的调用:
#include <iostream>#include <vector>#include <chrono>#include "ThreadPool.h"int main(){ ThreadPool pool(4); std::vector< std::future<int> > results; for(int i = 0; i < 8; ++i) { results.emplace_back( pool.enqueue([i] { std::cout << "hello " << i << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "world " << i << std::endl; return i*i; }) ); } for(auto && result: results) std::cout << result.get() << ' '; std::cout << std::endl; return 0;}
对上面的源码进行简单的剖析:
condition_variable头文件
头文件主要包含了与条件变量相关的类和函数。相关的类包括 std::condition_variable 和 std::condition_variable_any,还有枚举类型std::cv_status
可以参考:http://www.cnblogs.com/haippy/p/3252041.html
future头文件
前面已经多次提到过 std::future,那么 std::future 究竟是什么呢?简单地说,std::future 可以用来获取异步任务的结果,因此可以把它当成一种简单的线程间同步的手段。std::future 通常由某个 Provider 创建,你可以把 Provider 想象成一个异步任务的提供者,Provider 在某个线程中设置共享状态的值,与该共享状态相关联的 std::future 对象调用 get(通常在另外一个线程中) 获取该值,如果共享状态的标志不为 ready,则调用 std::future::get 会阻塞当前的调用者,直到 Provider 设置了共享状态的值(此时共享状态的标志变为 ready),std::future::get 返回异步任务的值或异常(如果发生了异常)。
一个有效(valid)的 std::future 对象通常由以下三种 Provider 创建,并和某个共享状态相关联。Provider 可以是函数或者类,其实我们前面都已经提到了,他们分别是:
参考:http://www.cnblogs.com/haippy/p/3280643.html
stdexcept头文件
定义了一些标准的异常类。分为两大类:逻辑错误和运行时错误。其中运行时错误是程序员不能控制的。
逻辑错误都继承自 logic_error
domain_error 域错误
invalid_argument 非法参数
length_error 通常是创建对象是给出的尺寸太大
out_of_range 访问超界
运行时错误都继承自runtime_error
overflow_error 上溢
range_error 超出表示范围
underflow_error 下溢
emplace_back和push_back的区别
emplace_back和push_back都是向容器内添加数据.
对于在容器中添加类的对象时, 相比于push_back,emplace_back可以避免额外类的复制和移动操作.
std::chrono
过定义这些常用的时间间隔类型,我们能方便的使用它们,比如线程的休眠:
std::this_thread::sleep_for(std::chrono::seconds(3)); //休眠三秒
std::this_thread::sleep_for(std::chrono:: milliseconds (100)); //休眠100毫秒
基于范围的for循环
基于范围的for循环是老生常谈了:
for(auto result:results)
如果要改变results的内容,则可使用引用:
for(auto & result:results)
那么这个是什么意思呢?
for(auto && result:results)
即:I will accept any initializer regardless of whether it is an lvalue or rvalue expression and I will preserve its constness
using定义别名
template<typename T>using Tlist = std::list<T>;
C++中构造函数和析构函数可以是内联函数吗
首先明确,这不是C++11新内容
无论是构造函数还是析构函数都可以声明为inline的:
class Foo { int* p;public: Foo(); ~Foo();};inline Foo::Foo() { p = new char[0x00100000]; }inline Foo::~Foo(){ delete [] p; }
需要明确是:
Defining the body of the constructor INSIDE the class has the same effect of placing the function OUTSIDE the class with the “inline” keyword.
In both cases it’s a hint to the compiler. An “inline” function doesn’t necessarily mean the function will be inlined. That depends on the complexity of the function and other rules.
lambda表达式
此处略去一千字
可变参数模板
此处略去一万字
- 分享一个C++11写的线程池
- 分享一个c线程池实现代码
- 写一个线程池
- 使用C++ 11特性写一个简单的线程池
- 写一个简单的线程池
- 分享:写了一个 java 调用 C语言 开发的动态库的范例
- 【分享】写的一个桌面应用程序
- 分享一个java写的简单计算器
- 写的一个简单的java线程池
- 用c++11写的一个线程安全的队列
- 一个C语言线程池的实现
- Java: 动手写一个简单的线程池
- 自己动手,写一个简单的线程池(1)
- 自己动手,写一个简单的线程池(2)
- 自己动手,写一个简单的线程池(3)
- 一个线程写一个线程读的队列
- 经验分享,如何写线程
- 分享一个用DHTML写的一个js简易轮播图
- 掌握Tiles 框架 (一)---Tiles入门和Tiles 框架和体系结构
- 抽象
- java匿名内部类
- 设计模式六大原则(2):里氏替换原则
- 接口
- 分享一个C++11写的线程池
- const 放在函数后表示的意思
- Timus 1327. Fuses
- 运算符一元,二元,三元
- 沙盒路径和本地数据存储方式plist/归档/偏好设置
- mac下常用快捷键
- lesson4_MFC实现单文档应用程序画线
- ZOJ3939 The Lucky Week
- [Java基础] 序列化与反序列化