代码从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. JAVA WEB开发环境搭建

    JAVA WED开发环境搭建 JDK的安装和配置 到https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-21 ...

  2. python 学习笔记一——Python安装和IDLE使用

    好吧,一直准备学点啥,前些日子也下好了一些python电子书,但之后又没影了.年龄大了,就是不爱学习了.那就现在开始吧. 安装python 3 Mac OS X会预装python 2,Linux的大多 ...

  3. PowerDesigner 16.5 安装和卸载教程【含有安装文件】

    1 下载 下载地址:https://pan.baidu.com/s/1kqly0d8qU-QluEagXwh53g 密码:n1a3 下载之后目录结构如下: 2 安装教程 1 安装 1.双击安装文件,如 ...

  4. JavaScript 闭包初认识

    1.简单的例子 首先从一个经典错误谈起,页面上有若干个div, 我们想给它们绑定一个onclick方法,于是有了下面的代码 <ul id="divTest"> < ...

  5. 初学Hadoop之WordCount词频统计

    1.WordCount源码 将源码文件WordCount.java放到Hadoop2.6.0文件夹中. import java.io.IOException; import java.util.Str ...

  6. javascript获取后台传来的json

    Mvc Razor视图引擎中 <script type="text/javascript"> var _temp = @(new MvcHtmlString(this. ...

  7. Cocos2d-js 开发记录:声音播放

    声音播放可以使用cc.audioEngine,需要播放的文件在resource.js中进行添加如: button_press_mp3: "res/audio/press.mp3", ...

  8. 微信小程序入门案例

    本文通过具体的实例记录微信小程序的入门知识. 1.特点 不需要安装 依赖微信应用 更接近原生APP 丰富的框架及API可达到快速开发的目的 2.工具使用 在开发的过程中可以使用微信开发者工具,更加直观 ...

  9. 详解JavaScript UTC时间转换方法

    这篇文章主要介绍了JavaScript UTC时间转换方法,介绍了本地时间到UTC时间的转换.UTC日期到本地日期的转换,感兴趣的小伙伴们可以参考一下 一.前言 1.UTC: Universal Ti ...

  10. Learn by pictures on Computer Fields