当前位置: 首页 > news >正文

理解线程池源码 【C++】面试高频考点

理解线程池 C++

文章目录

  • 理解线程池 C++
    • 程序源码
    • 知识点
      • emplace_back 和 push_back有什么区别?
      • 互斥锁 mutex
      • condition_variable
      • std::move()函数
      • bind()函数
      • join 函数

线程池的原理就是管理一个任务队列和一个工作线程队列。

工作线程不断的从任务队列取任务,然后执行。如果没有任务就等待新任务的到来。添加新任务的时候先添加到任务队列,然后通知任意(条件变量notify_one/notify_all)一个线程有新的任务来了。

优势包括:

  • 资源管理:线程池有效地管理线程的创建、销毁和重用,避免了频繁创建和销毁线程的开销,节省了系统资源。

  • 减少线程创建时间:线程创建和销毁是开销较大的操作。线程池在初始化时创建一组线程,并将它们保持在就绪状态,从而在需要时可以快速执行任务,而不必每次都重新创建线程。

  • 任务队列:线程池通常与任务队列结合使用,任务可以被提交到队列中,线程池中的线程会按照队列中任务的顺序依次执行,确保了任务的有序执行。

  • 限制并发数:线程池可以限制并发执行的任务数量,以避免系统资源过度占用,提高系统稳定性。

  • 节省内存:线程池的线程可以被重复使用,避免了频繁创建线程的内存占用。

应用场景包括:

服务器应用:线程池在服务器应用中常用来处理客户端请求。当服务器需要处理大量的连接请求时,线程池可以有效地复用线程,提高服务器性能。

I/O密集型任务:线程池适用于I/O密集型任务,如文件读写、网络通信等。在这些情况下,线程可以在I/O操作等待时执行其他任务,提高了系统的效率。

并行计算:线程池可以用于并行计算,将任务拆分为多个子任务,由线程池中的线程并行执行,加速计算过程。

定时任务:线程池可用于执行定时任务,例如定期备份数据、清理日志等。

多任务并行处理:当需要处理多个任务,但不想为每个任务创建一个线程时,线程池是一种有效的方式。它可以控制并发任务的数量,从而避免系统过度负载。

20231012153035

程序源码


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:// 线程组std::vector<std::thread> workers;// 任务队列std::queue<std::function<void()> > tasks;// synchronizationstd::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 = 0; i < threads; ++i)//thread 禁用了拷贝构造和赋值运算,因此这边最好用emplace_backworkers.emplace_back([this] {for (;;) {  //死循环的作用是一直让线程执行任务直至结束std::function<void()> task;{std::unique_lock<std::mutex> lock(this->queue_mutex);// 如果线程终止了 或者 任务队列不为空 就等待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
template <class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)-> std::future<typename std::result_of<F(Args...)>::type> {using return_type = typename std::result_of<F(Args...)>::type;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 poolif (stop) throw std::runtime_error("enqueue on stopped ThreadPool");tasks.emplace([task]() { (*task)(); });}condition.notify_one();return res;
}// the destructor joins all threads
inline ThreadPool::~ThreadPool() {{std::unique_lock<std::mutex> lock(queue_mutex);stop = true;}condition.notify_all();for (std::thread& worker : workers) worker.join();
}

知识点

emplace_back 和 push_back有什么区别?

《c++ primer》书里说明:

1.当调用push或insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中。而当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。emplace成员使用这些参数在容器管理的内存空间中直接构造元素。

2.其中对emplace_back的调用和第二个push_back调用都会创建新的Sales_data对象。在调用emplace_back时,会在容器管理的内存空间中直接创建对象。而调用push_back则会创建一个局部临时对象

3.标准库容器的emplace_back成员是一个可变参数成员模板,而push_back只能传入单个参数

20231010183634

总结就是emplace_back资源消耗更小,不会创建临时对象,同事可以进行多参数的传入,应用于像vector中T有多个参数的场景。

互斥锁 mutex

一种同步原语,用于多线程管理,确保临界资源只有一个线程访问,其中mtx.lock()表示上锁,mtx.unlock()表示解锁。上述线程池中为什么没有unlock呢?因 std::unique_lockstd::mutex 这个智能指针在退出{}代码块之后就会自动销毁。

condition_variable

condition_variable 条件变量是一种对象,能够阻止调用线程,直到收到通知才能恢复。一般配合 unique_lock 一起使用。当其中一个等待函数被调用时,线程保持阻塞状态,直到被另一个线程唤醒,该线程在同一condition_variable对象上调用通知函数。

//通过notify_one或者notify_all进行唤醒
void wait (unique_lock<mutex>& lck);
//只有pred返回false时才会阻塞,pred变为true时才能被唤醒
void wait (unique_lock<mutex>& lck, Predicate pred);

std::move()函数

左值变右值,可以参考C++ 左值右值以及std::move函数解释

bind()函数

每个参数可以绑定到一个值或者作为占位符:

  • 如果绑定到一个值,调用返回的函数对象将总是使用该值作为参数。
  • 如果作为占位符,调用返回的函数对象将转发传递给调用的参数(由占位符指定顺序号)
double my_divide (double x, double y) {return x/y;}int main () {auto fn_five = std::bind (my_divide,10,2);               // returns 10/2std::cout << fn_five() << '\n';                          // 5auto fn_half = std::bind (my_divide,_1,2);               // returns x/2std::cout << fn_half(10) << '\n';                        // 5auto fn_invert = std::bind (my_divide,_2,_1);            // returns y/xstd::cout << fn_invert(10,2) << '\n';                    // 0.2auto fn_rounding = std::bind<int> (my_divide,_1,_2);     // returns int(x/y)std::cout << fn_rounding(10,3) << '\n';                  // 3
}

join 函数

C++中用于线程同步的一个方法,它通常用于等待一个线程的执行完成。当你创建一个线程并希望等待它完成执行。

int main() {std::thread t1(foo);std::thread t2(bar);t1.join();  // 主线程等待 t1 完成t2.join();  // 主线程等待 t2 完成std::cout << "Both threads have finished!" << std::endl;return 0;
}

相关文章:

理解线程池源码 【C++】面试高频考点

理解线程池 C 文章目录 理解线程池 C程序源码知识点emplace_back 和 push_back有什么区别&#xff1f;互斥锁 mutexcondition_variablestd::move()函数bind()函数join 函数 线程池的原理就是管理一个任务队列和一个工作线程队列。 工作线程不断的从任务队列取任务&#xff0c;然…...

BP神经网络应用案例

目录 背景介绍 【神经网络符号说明】 【建立网络拓扑结构】 【神经网络学习步骤】 步骤1 准备输入和输出样本 步骤2 确定网络学习参数 步骤3 初始化网络权值W和阀值B 步骤4 计算网络第一层的输入和输出 步骤5 计算中间层&#xff08;隐含层输入和输出&#xff09; 步骤…...

日常学习记录随笔-大数据之日志(hadoop)收集实战

数据收集(nginx)--->数据分析---> 数据清洗--->数据聚合计算---数据展示 可能涉及到zabix 做任务调度我们的项目 电商日志分析 比如说我们现在有一个系统,我们的数仓建立也要有一个主题 我这个项目是什么我要干什么定义方向 对用户进行分析,用户信息 要懂整个数据的流…...

【云计算】相关解决方案介绍

文章目录 1.1 云服务环境 Eucalyptus1.1.1 介绍1.1.2 开源协议及语言1.1.3 官方网站 1.2 开源云计算平台 abiCloud1.2.1 开源协议及语言1.2.2 官方网站 1.3 分布式文件系统 Hadoop1.3.1 开源协议及语言1.3.2 官方网站 1.4 JBoss云计算项目集 StormGrind1.4.1 开源协议及语言1.4…...

攻防世界题目练习——Crypto密码新手+引导模式(二)(持续更新)

题目目录 1. 转轮机加密2. easychallenge 上一篇&#xff1a;攻防世界题目练习——Crypto密码新手引导模式&#xff08;一&#xff09;&#xff08;持续更新&#xff09; 1. 转轮机加密 首先了解一下轮转机加密吧。 传统密码学(三)——转轮密码机 题目内容如下&#xff1a; …...

LeetCode【1】两数之和

题目&#xff1a; 代码&#xff1a; public int[] twoSum(int[] nums, int target) {int[] result new int[2];Map<Integer, Integer> map new HashMap<>();// for (int i 0; i < nums.length; i) { // 这么写不能防重复啊&#xff01;注意这里不…...

【运维笔记】VMWare 另一个程序已锁定文件的一部分,进程无法访问

情景再现 这里使用的是VMware 17 解决办法 进入设置 点击选项&#xff0c;全选复制里面内容 进入文件夹&#xff0c;删除所有包含.lck后缀的文件和文件夹 再启动虚拟机即可...

[Springboot]统一响应和异常处理配置

背景 前后端分离情况下&#xff0c;后端接口通常只需要返回JSON数据。 但有时候因为某些原因可能会导致得不到正确的结果。 比如 因为登录密码错误&#xff0c;你不能直接返回错误信息和null&#xff0c;这样前端很难处理。 又比如 因为后端接口爆出了异常&#xff0c;也不能直…...

Redis第四五六章 持久化事务主从复制

Redis ⽀持 RDB 和 AOF 两种持久化机制&#xff0c;持久化功能有效地避免因进程退出造成数据丢失问题&#xff0c; 当下次重启时利⽤之前持久化的⽂件即可实现数据恢复。 目录 第四章 持久化 4.1 RDB 4.1.1 触发机制 4.1.2 流程说明 4.1.3 RDB ⽂件的处理 4.1.4 RDB 的优…...

【强烈推荐】免费的PDF工具,包括PDF拆分/分割、转WORD等功能的免费在线软件工具,救了大命,找了半天什么pdf365、福xipdf、还有哔果pdf全是打着免费名义收费,烦死了

PDF拆分 - 图文工具箱 - imgtool.net&#xff0c;嘎嘎好用&#xff0c;主要是免费 除此之外&#xff0c;还有其他的功能&#xff0c;需要的可以去看看...

SpringMVC源码分析(二)启动过程之RequestMappingHandlerMapping分析

a、http请求中的url是如何与对应Handler的即Controller对应method映射的&#xff1f; 在上篇中提到在SpringMVC中&#xff0c;初始化9大内置组件的时候其中有一个组件就是HandlerMapping&#xff0c;在初始化HandlerMapping的时候会加载代码中所有标注了Controller和RequestMap…...

KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(7)

接前一篇文章:KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(6) 上一回讲到了drm_internal_framebuffer_create函数中的framebuffer_check函数。讲解了该函数的参数检查部分中的第二部分,本回对于该函数余下部分进行解析。 为了便于理解,再次贴出framebuffer_ch…...

2023 年 Arm A-Profile 架构发展

随着人工智能 (AI) 的兴起和安全威胁的加剧,计算需求不断发展,作为世界设备核心的基础计算架构也必须不断发展。这就是为什么我们的工程团队向普遍存在的 Arm 架构添加新功能和技术,然后软件团队确保软件尽可能无缝地适应这些未来的功能和技术。 Arm架构是如何开发的 Arm …...

2023年09月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 Python编程(1~6级)全部真题・点这里 第1题:红与黑 有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。 时间限…...

CentOS系统/root根目录扩容(扩展逻辑卷)

具体操作步骤 1、查看本机磁盘环境挂载情况 2、添加磁盘分区 3、开始扩容 4、同步到文件系统 1、查看本机磁盘环境挂载情况 [rooticon ~]# df -lh 可以看到/dev/mapper/centos-root 路径下容量为50G&#xff0c;我们要给这个路径下的容量扩容&#xff1a;[rooticon ~]# lsblk…...

苍穹外卖(三) 员工分页及技术实现细节

2. 员工分页查询 2.1 需求分析和设计 2.1.1 产品原型 2.1.2 接口设计 2.2 代码开发 2.2.1 设计DTO类 根据请求参数进行封装 2.2.2 封装PageResult 后面所有的分页查询&#xff0c;统一都封装为PageResult对象。 员工信息分页查询后端返回的对象类型为: Result 2.…...

二进制部署MySQL8.0

1、下载MySQL官方包 ## 下载MySQL [rootlocalhost ~]# wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz2、解压并移动安装包 # 解压安装包 [rootlocalhost ~]# tar xf mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz# 移动 mv…...

全力以赴,火山引擎边缘云代表团出战亚运会

END 未来&#xff0c;火山引擎边缘云赛事阵容将继续全力以赴&#xff0c;通过领先、可信赖的云和智能技术&#xff0c;助力游戏行业呈现更加精彩的竞技赛事。...

WPF页面向后端传参

WPF页面&#xff08;前端&#xff09;向后端传参 1、编写一个Button&#xff0c;绑定后端命令&#xff0c;并传递参数&#xff1a; <ButtonWidth"100"Command"{Binding SendCommand}"CommandParameter"{Binding ElementNameSendMessage, PathTex…...

PyTorch 入门

一、说明 深度学习是机器学习的一个分支&#xff0c;其中编写的算法模仿人脑的功能。深度学习中最常用的库是 Tensorflow 和 PyTorch。由于有各种可用的深度学习框架&#xff0c;人们可能想知道何时使用 PyTorch。以下是人们更喜欢使用 Pytorch 来完成特定任务的原因。 Pytorch…...

微信自动批量添加好友的方法

在现在的营销中微信已成为一种重要的沟通方式。微信目前是没有自动批量添加好友的功能&#xff0c;需要运营者一个一个手动去添加&#xff0c;这样太过于浪费时间&#xff0c;并且加频繁了还容易被封号&#xff0c;今天给大家介绍几种手动批量加好友的方式以及怎么借助第三方软…...

[网鼎杯 2018]Comment git泄露 / 恢复 二次注入 .DS_Store bash_history文件查看

首先我们看到账号密码有提示了 我们bp爆破一下 我首先对数字爆破 因为全字符的话太多了 爆出来了哦 所以账号密码也出来了 zhangwei zhangwei666 没有什么用啊 扫一下吧 有git git泄露 那泄露看看 真有 <?php include "mysql.php"; session_start(); if(…...

生态兼容性进一步提升!白鲸开源 WhaleStudio 与火山引擎ByteHouse完成产品互认

数据作为新型生产要素&#xff0c;已快速融入生产、分配、流通、消费和社会服务管理等各环节&#xff0c;深刻改变着生产方式、生活方式和治理方式。越来越多企业也在尝试充分利用数据要素&#xff0c;开辟全新发展路径&#xff0c;进一步实现业务价值提升。 在数字化转型的大…...

iOS 内存管理和优化

对内存管理和拓展有独特的描述 iOS学习-内存管理 比较详细说明内存的关系 iOS 内存管理机制与原理 iOS 内存泄漏排查方法及原因分析 对weak的实现原理描写详细 【iOS】—— weak的基本原理 iOS copy & mutableCopy iOS 深拷贝与浅拷贝 对iOS的浅复制和深复制的深入解释…...

常见工具指令【Vim | GIT | ZIP | UNZIP | IDEA】

VIM 快捷键说明Ctrl U (up)向上翻动半页Ctrl B (back)向上翻动一页Ctrl D (down)向下翻页半页Ctrl F (forward)向下翻动一页 GIT 指令解释git init 使用指定目录作为Git仓库git add filename向资源库添加文件filenamegit rm file从资源库中删除文件git branch 分支名称创…...

中国人民大学与加拿大女王大学金融硕士——顺势而为,掌握人生的方向盘

在这个快速发展的时代&#xff0c;每个人在不断面临全新挑战的同时&#xff0c; 也在时刻接收着各种机会。有人抓住时代红利&#xff0c;实现更新迭代&#xff1b;有人却只能作为旁观者&#xff0c;眼看时代发展&#xff0c;而自己被逐渐淘汰。时代从不会抛下任何一个人&#x…...

Apache Ranger:(二)对Hive集成简单使用

1.Ranger Hive-plugin安装 进入 Ranger 编译生成的目录下 找到 ranger-2.0.0-hive-plugin.tar.gz 进行解压 tar -zxvf ranger-2.0.0-hive-plugin.tar.gz -C /opt/module/ 2.修改配置文件 vim install.properties #策略管理器的url地址 POLICY_MGR_URLhttp://[ip]:6080#组件…...

【angular】实现简单的angular国际化(i18n)

文章目录 目标过程运行在TS中国际化参考 目标 实现简单的angular国际化。本博客实现中文版和法语版。 将Hello i18n!变为中文版&#xff1a;你好 i18n!或法语版:Bonjour l’i18n !。 过程 创建一个项目&#xff1a; ng new i18nDemo在集成终端中打开。 添加本地化包&#…...

Redis之主从复制,哨兵模式,集群

Redis之主从复制&#xff0c;哨兵模式&#xff0c;集群 1、主从复制1.1主从复制概述1.2Redis主从复制作用1.3Redis主从复制流程1.4部署Redis 主从复制 2、哨兵模式2.1哨兵模式原理2.2哨兵模式的作用2.3哨兵模式的结构2.4故障转移机制2.5搭建Redis 哨兵模式 3、Redis集群模式3.1…...

掌动智能浅析Web自动化测试的重要性

在现代Web开发中&#xff0c;确保Web应用程序的质量和稳定性至关重要。Web自动化测试工具成为了开发团队的关键资源&#xff0c;帮助他们自动化测试流程、减少手动劳动&#xff0c;提高测试覆盖率和效率。本文将介绍Web自动化测试的重要性是什么! Web自动化测试的重要性&#x…...