代码从github上拷的,写了一些理解,如有错误请指正

Threadpool.h

 #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 workers
inline ThreadPool::ThreadPool(size_t threads)
: stop(false)
{
for(size_t i = ;i<threads;++i)
workers.emplace_back( //这里一下启动threads个,即使lambda阻塞(在已启动子线程内的阻塞),主线程还是会循环
[this]
{
for(;;)
{
std::function<void()> task; {
std::unique_lock<std::mutex> lock(this->queue_mutex); //当前线程被阻塞, 直到condition.notify_one()调用,如果lambda返回false,wait会解锁互斥元lock并置阻塞或等待状态,如果条件满足互斥元仍被锁定
//而这里锁用的是std::unique_lock而不是std::lock_guard,是因为std::lock_guard不能在wait等待中解锁,并在之后重新锁定
//如果互斥元在线程休眠期间始终被锁定,enqueue就无法锁定互斥元往下执行,则造成死锁
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 pool //函数后跟throw()代表不抛出任何异常,跟thorw(...)代表可以抛出任何异常
template<class F, class... Args> //... Args这个代表不限类型,不限数量
auto ThreadPool::enqueue(F&& f, Args&&... args) //&&代表右值引用(可以用常量做参数)
-> std::future<typename std::result_of<F(Args...)>::type> //<F(Args...)>代表这个是个返回类型为F,参数不确定多的函数;放入类型(如int)会报错
{
using return_type = std::result_of<F(Args...)>::type; //std::result_of::type 获得函数返回类型,直接用decltype会报错 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(); ////选择一个wait状态的线程进行唤醒,并使他获得对象上的锁来完成任务(即其他线程无法访问对象)
return res;
} // the destructor joins all threads
inline ThreadPool::~ThreadPool()
{
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all(); //通知所有wait状态的线程竞争对象的控制权,唤醒所有线程执行
for(std::thread &worker: workers)
worker.join();
} #endif

运行代码

 #include "stdafx.h"
#include <iostream>
#include <vector>
#include <chrono> #include "ThreadPool.h" int main()
{ ThreadPool pool();
std::vector< std::future<int> > results; for(int i = ; i < ; ++i) {
results.emplace_back(
pool.enqueue([i] {
std::cout << "hello " << i << std::endl;
std::this_thread::sleep_for(std::chrono::seconds());
std::cout << "world " << i << std::endl;
return i*i;
})
);
} for(auto && result: results)
std::cout << result.get() << ' ';
std::cout << std::endl;
system("pause");
return ;
}

c++11之100行实现简单线程池的更多相关文章

  1. 基于C++11的100行实现简单线程池

    基于C++11的100行实现简单线程池 1 线程池原理 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小, ...

  2. Linux多线程实践(9) --简单线程池的设计与实现

    线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...

  3. Linux下简单线程池的实现

    大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的.在传统的多线程服务器模型中是这样实现的:一旦有个服务请求到达,就创建一个新的服务 ...

  4. 【C++11应用】基于C++11及std::thread实现的线程池

    目录 基于C++11及std::thread实现的线程池 基于C++11及std::thread实现的线程池 线程池源码: #pragma once #include <functional&g ...

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

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

  6. C语言实现简单线程池(转-Newerth)

    有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程池.下面是一个C语言实现的简单的线程池. 头文件: 1: #ifndef THREAD_POOL ...

  7. LINUX下的简单线程池

    前言 任何一种设计方式的引入都会带来额外的开支,是否使用,取决于能带来多大的好处和能带来多大的坏处,好处与坏处包括程序的性能.代码的可读性.代码的可维护性.程序的开发效率等. 线程池适用场合:任务比较 ...

  8. Linux简单线程池实现(带源码)

    这里给个线程池的实现代码,里面带有个应用小例子,方便学习使用,代码 GCC 编译可用.参照代码看下面介绍的线程池原理跟容易接受,百度云下载链接: http://pan.baidu.com/s/1i3z ...

  9. 使用c++11写个最简跨平台线程池

    为什么需要多线程? 最简单的多线程长啥样? 为什么需要线程池,有什么问题? 实现的主要原理是什么? 带着这几个问题,我们依次展开. 1.为什么需要多线程? 大部分程序毕竟都不是计算密集型的,简单的说, ...

随机推荐

  1. rancher1.X+docker+k8s搭建容器管理集群

    一, 环境准备 服务器 Linux k8s-m -.el7.x86_64 #1 SMP Fri Apr 20 16:44:24 UTC 2018 x86_64 x86_64 x86_64 GNU/Li ...

  2. python3初探

      官方网站:https://www.python.org/ 类库大全:https://pypi.python.org/pypi 基础类库:https://docs.python.org/3/libr ...

  3. 第十五章:集成JPUSH

    如果不想自己搭建push server,则可以借助于第三方的api来实现push的功能,本文主要介绍ionic如何集成jpush. 具体步骤如下: 创建ionic应用:ionic_jpush. 申请j ...

  4. 阿里云Tomcat运行shutdown.sh命令关闭时遇到的问题

    1.安装完成jdk之后,然后安装tomcat. tomcat安装成功后,进入tomcat的安装目录,找到bin所在的目录. 使用./startup.sh,启动tomcat; 使用./shutdown. ...

  5. 案例43-crm练习获取客户列表使用struts2

    1 src下配置文件 1 struts.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYP ...

  6. linux下memcached的启动/结束的方式

    当前项目中,linux下memcached的启动/结束的方式 默认情况下memcached安装到/usr/local/bin下. 进入安装目录,启动memcached:/usr/local/memca ...

  7. java url生成二维码保存到本地

    http://blog.sina.com.cn/s/blog_5a6efa330102v1lb.html http://blog.csdn.net/about58238/article/details ...

  8. 随机森林(Random Forests)

    简单地看了一些入门的资料. 随机森林似乎和CART有些联系. 随机森林的算法步骤: 1. 利用自助法(Bootstrap)从原始训练集中生成k个自助样本集,每个自助样本集是每棵分类树的全部训练数据.自 ...

  9. a标签的 onclick 和 href 哪个先执行?

    以下这种写法,onclick 事件先执行, href 属性下的动作后执行(页面跳转或 javascript 伪链接),如果不想执行 href 属性下的动作,onclick 需要返回 false. &l ...

  10. PHP常用数组操作方法汇总

    array_change_key_case -- 返回字符串键名全为小写或大写的数组array_chunk -- 将一个数组分割成多个array_combine -- 创建一个数组,用一个数组的值作为 ...