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

1 线程池原理

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。

线程池组成部分:

线程池管理器:用于创建并管理线程池

工作线程: 线程池中实际执行的线程

任务接口: 尽管线程池大多数情况下是用来支持网络服务器,但是我们将线程执行的任务抽象出来,形成任务接口,从而是的线程池与具体的任务无关。

任务队列:线程池的概念具体到实现则可能是队列,链表之类的数据结构,其中保存执行线程。

2 并发下线程池的最佳数量

如果是CPU密集型应用,则线程池大小设置为N+1;(对于计算密集型的任务,在拥有N个处理器的系统上,当线程池的大小为N+1时,通常能实现最优的效率。(即使当计算密集型的线程偶尔由于缺失故障或者其他原因而暂停时,这个额外的线程也能确保CPU的时钟周期不会被浪费。摘自《Java Concurrency In Practise》)。因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,只能增加上下文切换的次数,因此会带来额外的开销。I
如果是IO密集型应用,则线程池大小设置为2N+1;IO密集型任务可以使用稍大的线程池,一般为2*CPU核心数。IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候去处理别的任务,充分利用CPU时间。

2.1 线程池是否一定比单线程高效?

答案是否定的,比如Redis就是单线程的,但它却非常高效,基本操作都能达到十万量级/s。从线程这个角度来看,部分原因在于:多线程带来线程上下文切换开销,单线程就没有这种开销 锁

当然“Redis很快”更本质的原因在于: 
Redis基本都是内存操作,这种情况下单线程可以很高效地利用CPU。而多线程适用场景一般是:存在相当比例的IO和网络操作。

3 线程池设计的C++11的特性

  • std::vector
  • std::thread
  • std::mutex
  • std::future
  • std::condition_variable

C++代码:

threadpool.h

#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <stdexcept> const int MAX_THREADS = ; // 线程池阈值 template <typename T>
class threadpool
{
public:
threadpool(int number = ); // 线程池构造函数,传入线程数,默认为1
~threadpool(); // 线程池析构函数
bool append(T* request); // 添加任务到任务队列 private:
static void* worker(void* arg); // 工作线程数组
void run(); // 工作线程的执行函数 private:
std::vector<std::thread> work_threads; // 工作线程
std::queue<T*> task_queues; // 任务队列
std::mutex queue_mutex; // 队列互斥锁
std::condition_variable condition; // 条件变量
bool stop; // 停止标志
}; template <typename T>
threadpool<T>::threadpool(int number) :stop(false)
{
if (number <= || number > MAX_THREADS) // 如果number小于等于0或者大于线程池阈值,抛出异常
throw std::exception(); for (int i = ; i < number; i++)
{
std::cout << "创建第" << i << "个线程" << std::endl;
// 添加worker函数到线程中
work_threads.emplace_back(worker, this); // Q:this是什么作用,为什么没了this会出错?
}
} template <typename T>
inline threadpool<T>::~threadpool()
{
{
std::unique_lock<std::mutex> lock(queue_mutex); // 拿锁
stop = true; // 停止标志置位true
}
condition.notify_all(); // 通知所有工作线程,唤醒后因为stop为true了,所有都会结束
for (auto& ww : work_threads)
ww.join();
} template <typename T>
bool threadpool<T>::append(T* request) // 添加一个新的工作任务到任务队列
{
{
std::unique_lock<std::mutex> lock(queue_mutex);
task_queues.emplace(request); // 将任务添加到任务队列
}
condition.notify_one(); // 发送通知,唤醒某一个工作线程执行任务
return true;
} template <typename T>
void* threadpool<T>::worker(void* arg)
{
threadpool* pool = (threadpool*)arg;
pool->run();
return pool;
} template <typename T>
void threadpool<T>::run()
{
while (!stop)
{
std::unique_lock<std::mutex> lk(queue_mutex); // 拿锁(独占所有权式)
this->condition.wait(lk, [this] {return !this->task_queues.empty(); }); // 等待条件成立
/*
执行条件变量等待的时候,已经拿到了锁(即lock已经拿到锁,没有阻塞)
这里将会unlock释放锁,其他线程可以继续拿锁,但此处仍然阻塞,等待条件成立
一旦收到其他线程notify_*唤醒,则再次lock,然后进行条件判断
当{return !this->task_queues.empty(); }的结果为false将阻塞
条件为true时候解除阻塞。此时lock依然为锁住状态
*/
if (this->task_queues.empty()) // 如果任务队列为空,继续
continue;
else
{
T* request = task_queues.front(); // 取得任务队列首任务
task_queues.pop(); // 从队列中移除
if (request)
request->process(); // 执行任务
}
}
}

main.cpp

#include <iostream>
#include "threadpool.h" class Task
{
public:
void process()
{
static int a = ;
++a;
std::cout << "run......" << a << std::endl;
}
}; int main()
{
threadpool<Task> tp(); while ()
{
std::this_thread::sleep_for(std::chrono::milliseconds()); Task* t = new Task();
tp.append(t);
delete t;
}
}

参考:

https://blog.csdn.net/gcola007/article/details/78750220

https://blog.csdn.net/qq_34417408/article/details/78895573

基于C++11的100行实现简单线程池的更多相关文章

  1. c++11之100行实现简单线程池

    代码从github上拷的,写了一些理解,如有错误请指正 Threadpool.h #ifndef THREAD_POOL_H #define THREAD_POOL_H #include <ve ...

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

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

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

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

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

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

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

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

  6. 基于Linux/C++简单线程池的实现

    我们知道Java语言对于多线程的支持十分丰富,JDK本身提供了很多性能优良的库,包括ThreadPoolExecutor和ScheduleThreadPoolExecutor等.C++11中的STL也 ...

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

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

  8. LINUX下的简单线程池

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

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

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

随机推荐

  1. python全栈测试之路-py3基础:基础的常用语法知识

    python基础链接 python3速查参考- python基础 2 -> if语句应用 + while循环应用 https://www.cnblogs.com/wuzhiming/p/7795 ...

  2. OpenGL学习(4)——纹理(补)

    完成章节后练习 练习 1. Make sure only the happy face looks in the other/reverse direction by changing the fra ...

  3. Go语言中使用切片(slice)实现一个Vector容器

    Go语言中的切片(slice)和一些内置函数能实现其他语言容器类Array.Vector的功能,但是Go内置语言包container里只提供了list.heap.ring三种容器,缺少vector容器 ...

  4. yso中URLDNS的pop链分析(重新分析整理)

    #发现之前对这个链关注的点有点问题,重新分析了一下 由于最近面试的过程中被问到了yso中URLDNS这个pop链的工作原理,当时面试因为是谈到shiro的怎么检测和怎么攻击时谈到了这个.其实在实战中用 ...

  5. Windows系统Python直接调用C++ DLL

    环境:Window 10,VS 2019, Python 2.7.12, 64bit 1,打开 VS 2019,新建C++ Windows 动态链接库工程 Example,加入下列文件,如果Pytho ...

  6. shell学习笔记1-文件安全与权限

    1,创建文件的用户和他所属的组拥有该文件,文件的属主可以设定谁具有读.写.执行该文件的权限,根用户可以改变任何普通用户的设置. 2,一个文件一经创建,就具有三种访问权限:读(可以显示该文件的内容).写 ...

  7. 【ARM-Linux开发】cmem模块/DVSDK2.0

    1. CMEM--高速缓存一致性问题的解决多核设计中,共享的二级高速缓存之间数据可能不一致,不同CPU内核的私有高速缓存也可能存在数据不一致,称为高速缓存的一致性问题.解决一致性问题的方法从整体上分可 ...

  8. 最新 汇量科技java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿. 汇量科技等10家互联网公司的校招Offer,因为某些自身原因最终选择了 汇量科技.6.7月主要是做系统复习.项目复盘.Le ...

  9. #论文阅读# Universial language model fine-tuing for text classification

    论文链接:https://aclweb.org/anthology/P18-1031 对文章内容的总结 文章研究了一些在general corous上pretrain LM,然后把得到的model t ...

  10. [转帖]万能数据库的使用【DbVisualizer软件,连接不同类型的数据库】

    万能数据库的使用[DbVisualizer软件,连接不同类型的数据库] https://www.cnblogs.com/FanSunny/p/4874572.html 自己就是用这个工具进行处理的. ...