线程池学习

github看到一个项目(GitHub - markparticle/WebServer: C++ Linux WebServer服务器),内部使用的一个线程池看着不错,拿来学习一下。

/** @Author       : mark* @Date         : 2020-06-15* @copyleft Apache 2.0*/ #ifndef THREADPOOL_H
#define THREADPOOL_H#include <mutex>
#include <condition_variable>
#include <queue>
#include <thread>
#include <functional>
class ThreadPool {
public:explicit ThreadPool(size_t threadCount = 8): pool_(std::make_shared<Pool>()) {assert(threadCount > 0);for(size_t i = 0; i < threadCount; i++) {std::thread([pool = pool_] {std::unique_lock<std::mutex> locker(pool->mtx);while(true) {if(!pool->tasks.empty()) {auto task = std::move(pool->tasks.front());pool->tasks.pop();locker.unlock();task();locker.lock();} else if(pool->isClosed) break;else pool->cond.wait(locker);}}).detach();}}ThreadPool() = default;ThreadPool(ThreadPool&&) = default;~ThreadPool() {if(static_cast<bool>(pool_)) {{std::lock_guard<std::mutex> locker(pool_->mtx);pool_->isClosed = true;}pool_->cond.notify_all();}}template<class F>void AddTask(F&& task) {{std::lock_guard<std::mutex> locker(pool_->mtx);pool_->tasks.emplace(std::forward<F>(task));}pool_->cond.notify_one();}private:struct Pool {std::mutex mtx;std::condition_variable cond;bool isClosed;std::queue<std::function<void()>> tasks;};std::shared_ptr<Pool> pool_;
};#endif //THREADPOOL_H

1,先看下 私有变量。

struct Pool {std::mutex mtx;std::condition_variable cond;bool isClosed;std::queue<std::function<void()>> tasks;};
std::shared_ptr<Pool> pool_;

一个结构体 Pool 将用到的变量,全部包含进去。

mtx 一个锁,用于加入,取出任务。

cond 信号量,用于线程间同步。

isClosed 线程池退出的标志。

tasks 任务队列,存放所有需要在线程中执行的任务。

pool_ 智能指针,管理所有资源。

2,构造函数

(1),默认开启8个线程(size_t threadCount = 8),并在初始化列表中  初始化pool_对象(std::make_shared<Pool>())

(2),循环启动每个线程

for(){std::thread({//todo}).detach();
}

(3),加锁  确保 ,各个线程对 任务队列(tasks) 不产生竞争,因为添加任务,取任务都要操作这个队列。

std::unique_lock<std::mutex> locker(pool->mtx);

(4),单独看一个线程。

首先判断任务队列是否为空,为空 则利用信号量阻塞当前线程。

else pool->cond.wait(locker);

如果线程池是退出状态,则跳出当前循环,当前线程也会退出。

else if(pool->isClosed) break;

如果任务队列不为空,则取出第一个任务,队列减1,然后解锁,执行任务,再加锁。

auto task = std::move(pool->tasks.front());
pool->tasks.pop();
locker.unlock();
task();
locker.lock();

std::move 用于移动语义,允许在不复制内存的情况下转移资源的所有权。这段代码之后,相当于8个线程,从任务队列tasks 中抢任务,抢到一个执行一个。比如A线程 抢到了任务1,任务1 在执行中过程中,由于队列处于未加锁状态,那B线程,就可以继续抢任务2。

3,添加任务

std::forward ,在一个函数中将参数以原始的形式传递给另一个函数,同时保持其值类别(lvalue 或 rvalue)和 const 修饰符。

这里将task 添加到 任务队列 tasks中。并且利用locker 进行保护。这里添加完成之后,上述的8个线程就会从这个任务队列中抢任务,然后执行。

    template<class F>void AddTask(F&& task) {{std::lock_guard<std::mutex> locker(pool_->mtx);pool_->tasks.emplace(std::forward<F>(task));}pool_->cond.notify_one();}

3,销毁

将isClosed 标志置为false,并通知所有线程继续执行,防止因为任务队列为空,造成阻塞无法退出。在上述循环中,检测到isClosed 为fasel,则while循环退出,线程退出。

    ~ThreadPool() {if(static_cast<bool>(pool_)) {{std::lock_guard<std::mutex> locker(pool_->mtx);pool_->isClosed = true;}pool_->cond.notify_all();}}

5,使用

构造完ThreadPool 之后,直接调用AddTask ,将任务传入其中即可。

std::bind  用于创建一个可调用对象,将其与特定的参数绑定在一起。

 在C++11 之下,封装一个线程池 还是很优雅的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/504067.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Excel PDF 系列】EasyExcel + iText 库实现 Excel 转换 PDF

你知道的越多&#xff0c;你不知道的越多 点赞再看&#xff0c;养成习惯 如果您有疑问或者见解&#xff0c;欢迎指教&#xff1a; 企鹅&#xff1a;869192208 文章目录 前言转换前后效果引入 pom 配置代码实现定义 ExcelDataVo 对象主方法EasyExcel 监听器 前言 最近遇到生成 …

【Android开发】01-第一个Android APP

一、改MainActivity class MainActivity : AppCompatActivity() {/*因Android的app有生命周期&#xff0c;故入口是OnCreate而不是main函数*/override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main…

Java教程:SpringBoot项目如何对接Nacos实现服务发现治理,配置管理

–Nacos大家都知道&#xff0c;不懂的可以去官网或者网上查阅一下&#xff0c;本次给大家讲解一下如何在SpringBoot项目中引入Nacos服务来进行服务治理与发现&#xff0c;配置管理等&#xff0c;在微服务当中是必不可少的&#xff0c;各个模块之间可以通过Feign远程调用&#x…

Python的循环结构练习

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 生命对某些人来说是美丽的&#xff0c…

爬取某牙视频

爬取页面链接&#xff1a;游戏视频_游戏攻略_虎牙视频 爬取步骤&#xff1a;点进去一个视频播放&#xff0c;查看media看有没有视频&#xff0c;发现没有。在xhr中发现有许多ts文件&#xff0c;但这种不是很长的视频一般都有直接的播放链接&#xff0c;所以目标还是找直接的链…

PYTHON 自动化办公:压缩图片(PIL)

1、介绍 在办公还是学习过程中&#xff0c;难免会遇到上传照片的问题。然而照片的大小限制一直都是个问题&#xff0c;例如照片限制在200Kb之内&#xff0c;虽然有很多图像压缩技术可以实现&#xff0c;但从图像处理的专业来说&#xff0c;可以利用代码实现 这里使用的库函数是…

基于正态分布的序列选择策略及其在因果关系和平衡定律中的应用

题目&#xff1a;基于正态分布的序列选择策略及其在因果关系和平衡定律中的应用 摘要&#xff1a; 本文提出了一种基于正态分布的序列选择策略&#xff0c;并将其应用于因果关系和平衡定律的研究中。通过对一个长度为1000的序列进行随机打乱&#xff0c;并选择使序列的方差和均…

1.亿级积分数据分库分表:总体方案设计

项目背景 以一个积分系统为例&#xff0c;积分系统最核心的有积分账户表和积分明细表&#xff1a; 积分账户表&#xff1a;每个用户在一个品牌下有一个积分账户记录&#xff0c;记录了用户的积分余额&#xff0c;数据量在千万级积分明细表&#xff1a;用户每次积分发放、积分扣…

【leetcode】 剑指 Offer学习计划(java版本含注释)(下)

目录 前言第十六天&#xff08;排序&#xff09;剑指 Offer 45. 把数组排成最小的数&#xff08;中等&#xff09;剑指 Offer 61. 扑克牌中的顺子&#xff08;简单&#xff09; 第十七天&#xff08;排序&#xff09;剑指 Offer 40. 最小的k个数&#xff08;简单&#xff09; 第…

Redis 之五:Redis 的主从复制

概念 主从复制&#xff0c;是指将一台 Redis 服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(master)&#xff0c;后者称为从节点(slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。 默认情况下&#xff0c;每台Redis服务器都是主节…

Pytorch中张量的高级选择操作

在某些情况下&#xff0c;我们需要用Pytorch做一些高级的索引/选择&#xff0c;所以在这篇文章中&#xff0c;我们将介绍这类任务的三种最常见的方法&#xff1a;torch.index_select, torch.gather and torch.take 我们首先从一个2D示例开始&#xff0c;并将选择结果可视化&am…

日志到filebeat-->logstash-->elastic-->kibana

1、日志到filebeat。 cat /etc/filebeat/filebeat.yml filebeat.inputs: - type: syslog format: rfc3164 protocol.udp: host: "0.0.0.0:514" output.logstash: hosts: ["localhost:5044"] 验证方式: tcpdump -i 网卡名称 udp port 514 2、…