代码从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. TCP/IP网络通信-数据传输

    1.通过网络IP实现数据的传输. 2.服务器端代码  [ 服务端主要通过Socket类来创建一个监听等待客户端连接,服务端发送用send方法,接收用Receive方法] using System.Ne ...

  2. Python学习 day08

    一.open打开文件 文件操作包含以下三个步骤: 1.文件路径 2.编码方式 3.操作方式:‘’只读‘’.“只写”.“读写” 等 1.只读 r (mode默认值) 例: f = open('d:\py ...

  3. Oracle 基础系列之1.1 oracle的安装

    一. 1.以下是安装Oracle的一些硬件上的条件: (1).操作系统最后是windows2000(也就是服务器版的操作系统) (2).内存最好在1G以上,当然越大越好(因为Oracle服务启动就要消 ...

  4. 0.数据结构(python语言) 基本概念 算法的代价及度量!!!

    先看思维导图: *思维导图有点简陋,本着循循渐进的思想,这小节的知识大多只做了解即可. *重点在于算法的代价及度量!!!查找资料务必弄清楚. 零.四个基本概念 问题:一个具体的需求 问题实例:针对问题 ...

  5. Hibernate 缓存机制详细解析

    一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数 ...

  6. WCF入门教程通信(二)

    一.概述 WCF能够建立一个跨平台的安全.可信赖.事务性的解决方案,是一个WebService,.Net Remoting,Enterprise Service,WSE,MSMQ的并集,有一副很经典的 ...

  7. bzoj 5329: [Sdoi2018]战略游戏

    Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...

  8. Oracle新手常遇到的问题

    1.问题描述:尝试加载 Oracle 客户端库时引发 BadImageFormatException.如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题. 解决方 ...

  9. info.plist 安全登录

    设置info.plist 安全登录 App Transport Security Settings  dictionary Allow Arbitrary Loads  Boolean  YES

  10. Redis 的Hashs(哈希表)数据类型

    在Memcached中,我们经常将一些结构化的信息打包成hashmap,在客户端序列化后存储为一个字符串的值,比如用户的昵称.年龄.性别.积分等,这时候在需要修改其中某一项时,通常需要将所有值取出反序 ...