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

异步操作实现线程池

文章目录

  • future
    • async
    • promise
    • package task
  • C++11线程池实现

future

在C++11标准库中,提供了一个future的模板类,它表示的是一个异步操作的结果,当在多线程编程中使用异步任务的时候,使用这个类可以帮助在需要的时候获取到对应的数据处理结果,而future类本质上的一个重要特性是可以阻塞当前线程,直到异步操作完成,而确保在获取结果的时候不会出现结果未完成的情况出现

应⽤场景

  • 异步任务:当我们需要在后台执⾏⼀些耗时操作时,如⽹络请求或计算密集型任务等,std::future
    可以⽤来表⽰这些异步任务的结果。通过将任务与主线程分离,我们可以实现任务的并⾏处理,从
    ⽽提⾼程序的执⾏效率

  • 并发控制:在多线程编程中,我们可能需要等待某些任务完成后才能继续执⾏其他操作。通过使⽤
    std::future,我们可以实现线程之间的同步,确保任务完成后再获取结果并继续执⾏后续操作

  • 结果获取:std::future提供了⼀种安全的⽅式来获取异步任务的结果。我们可以使⽤
    std::future::get()函数来获取任务的结果,此函数会阻塞当前线程,直到异步操作完成。这样,在
    调⽤get()函数时,我们可以确保已经获取到了所需的结果

下面来看官方文档对于这个类的讲述:

在这里插入图片描述
大体意思是,future会作为一个返回值来进行接收,可以通过下面的三种方式来进行调用,这里展示第一种:async

async

在这里插入图片描述
在这个函数当中,就是一个经典的调用异步操作来执行的操作,对于函数参数来说,Fn表示的是这是一个要执行的函数,后面的args表示的是这个函数的参数,而对于这个函数来说,它存在一种函数的重载,这个函数的重载可以在最前面加上一个调用的策略,可以使得是立刻进行执行和获取函数的返回值,或者是在调用get函数再进行函数返回值的获取,下面使用一个实例代码来进行演示

std::async是⼀种将任务与std::future关联的简单⽅法。它创建并运⾏⼀个异步任务,并返回⼀个与该任务结果关联的std::future对象。默认情况下,std::async是否启动⼀个新线程,或者在等待future时,任务是否同步运⾏都取决于你给的参数。这个参数为std::launch类型:

  • std::launch::deferred表明该函数会被延迟调⽤,直到在future上调⽤get()或者wait()才会开始
    执⾏任务
  • std::launch::async 表明函数会在⾃⼰创建的线程上运⾏
  • std::launch::deferred | std::launch::async 内部通过系统等条件⾃动选择策略
#include <chrono>
#include <iostream>
#include <future>
#include <thread>
using namespace std;// 模拟一个加法的环境
int add(int num1, int num2)
{cout << "加法" << endl;return num1 + num2;
}void deferred_solve()
{cout << "deferred" << endl;cout << "------1------" << endl;future<int> fut = async(launch::deferred, add, 10, 20);cout << "------2------" << endl;this_thread::sleep_for(chrono::seconds(1));cout << "------3------" << endl;int res = fut.get();cout << "------4------" << endl;cout << "运行结果" << res << endl;
}void async_solve()
{cout << "async" << endl;cout << "------1------" << endl;future<int> fut = async(launch::async, add, 10, 20);cout << "------2------" << endl;this_thread::sleep_for(chrono::seconds(1));cout << "------3------" << endl;int res = fut.get();cout << "------4------" << endl;cout << "运行结果" << res << endl;
}int main()
{cout << "deferred: " << endl;deferred_solve();cout << endl;cout << "async: " << endl;async_solve();cout << endl;return 0;
}

运行结果如下所示:

deferred: 
deferred
------1------
------2------
------3------
加法
------4------
运行结果30async: 
async
------1------
------2------
加法
------3------
------4------
运行结果30

从上可以看出一些端倪,对于deferred这种策略来说,它的策略是在进行get方法的时候再进行资源的计算,而对于async这样的策略来说,更多的是在进行调用之后就会进行计算,在这种调用之后,会立刻再开一个工作线程把内容计算完毕后传递回主函数,这是两个基本的调用逻辑。

promise

std::promise提供了⼀种设置值的⽅式,它可以在设置之后通过相关联的std::future对象进⾏读取。换
种说法就是之前说过std::future可以读取⼀个异步函数的返回值了,但是要等待就绪,⽽std::promise就提供⼀种⽅式⼿动让std::future就绪

#include <iostream>
#include <thread>
#include <future>using namespace std;void add(int num1, int num2, promise<int>& pro)
{pro.set_value(num1 + num2);return;
}int main()
{promise<int> pro;future<int> fut = pro.get_future();thread th(add, 10, 20, ref(pro));int res = fut.get();cout << "执行结果: " << res << endl;th.join();return 0;
}

这个场景本质上就是利用了一个promise对象来和future对象建立了关系,如果在获取future对象的时候并没有发生值改变,就会阻塞等待,保证了异步的基本进行

package task

对于这种调用的方式,可以把它生成的对象当成是一个可调用对象,下面演示其基本用法

#include <iostream>
#include <thread>
#include <future>
#include <memory>
using namespace std;int add(int num1, int num2)
{return num1 + num2;
}int main()
{auto ptask = make_shared<packaged_task<int(int, int)>>(add);future<int> fut = ptask->get_future();thread th([ptask](){(*ptask)(10, 20);});int sum = fut.get();cout << sum << endl;th.join();return 0;
}

C++11线程池实现

基于线程池执⾏任务的时候,⼊⼝函数内部执⾏逻辑是固定的,因此选择std::packaged_task加上std::future的组合来实现。
线程池的⼯作思想:

  • ⽤⼾传⼊要执⾏的函数,以及需要处理的数据(函数的参数),由线程池中的⼯作线程来执⾏函数完成任务

实现:

  1. 管理的成员
  • 任务池:⽤vector维护的⼀个函数任务池⼦
  • 互斥锁&条件变量:实现同步互斥
  • ⼀定数量的⼯作线程:⽤于不断从任务池取出任务执⾏任务
  • 结束运⾏标志:以便于控制线程池的结束。
  1. 管理的操作:
  • ⼊队任务:⼊队⼀个函数和参数
  • 停⽌运⾏:终⽌线程池
#include <features.h>
#include <iostream>
#include <functional>
#include <memory>
#include <thread>
#include <future>
#include <mutex>
#include <condition_variable>
#include <vector>
using namespace std;class threadpool
{using Functor = function<void(void)>;
public:threadpool(int count = 1) : _stop(false){for(int i = 0; i < count; i++)_threads.emplace_back(&threadpool::entry, this);}~threadpool(){ stop();}void stop(){if(_stop == true)return;_stop = true;// 唤醒线程_cv.notify_all();// 回收线程for(auto& thread: _threads)thread.join();}// 对于push函数,传入的是一个用户要执行的函数,还有函数的参数// push函数的内部,会把这些传入的函数和参数封装为一个packaged_task// 然后使用lambda表达式生成一个可调用对象,放到任务池中,让工作线程取出执行template<typename F, typename ...Args>auto push(const F&& func, Args&& ...args) -> future<decltype(func(args...))>{// 1. 把传入的函数封装为一个packaged任务// 把返回类型获取出来using return_type = decltype(func(args...));// 把函数对象和函数参数绑定到一起auto tmp_func = bind(forward<F>(func), forward<Args>(args)...);// 把整体的tmp_func绑定成一个任务auto task = make_shared<packaged_task<return_type()>>(tmp_func);future<return_type> fut = task->get_future();// 2. 构造一个lambda匿名函数,函数内执行任务对象{unique_lock<mutex> lock(_mutex);// 3. 把匿名函数对象放到任务池中_taskpool.push_back([task](){ (*task)(); });_cv.notify_one();}return fut;}
private:void entry(){while(!_stop){vector<Functor> tmp_taskpool;{unique_lock<mutex> lock(_mutex);_cv.wait(lock, [this](){ return _stop || !_taskpool.empty(); });tmp_taskpool.swap(_taskpool);}for(auto& task : tmp_taskpool)task();}}
private:atomic<bool> _stop;vector<Functor> _taskpool;mutex _mutex;condition_variable _cv;vector<thread> _threads;
};

相关文章:

异步操作实现线程池

文章目录 futureasyncpromisepackage task C11线程池实现 future 在C11标准库中&#xff0c;提供了一个future的模板类&#xff0c;它表示的是一个异步操作的结果&#xff0c;当在多线程编程中使用异步任务的时候&#xff0c;使用这个类可以帮助在需要的时候获取到对应的数据处…...

长期提供APX515/B原装二手APX525/B音频分析仪

Audio Precision APx515 是一款针对生产测试而优化的高性能音频分析仪。它因其速度、性能、自动化和易用性而成为一流的仪器。它具有卓越的性能&#xff0c;具有 –106 dB 的典型 THDN、1M 点 FFT 和 192k 数字 I/O&#xff0c;以及所有 APx 系列音频分析仪的一键式自动化和易用…...

【数据库差异研究】update与delete使用表别名的研究

目录 ⚛️总结 ☪️1 Update ♋1.1 测试用例UPDATE users as a SET a.age 111 WHERE a.name Alice; ♏1.2 测试用例UPDATE users as a SET a.age 111 WHERE name Alice; ♐1.3 测试用例UPDATE users as a SET age 111 WHERE a.name Alice; ♑1.4 测试用例UPDATE us…...

idea远程连接docker

idea远程连接docker docker、ubuntu、linux、远程连接、IntelliJ idea注意&#xff01;本文中开启docker远程连接的方法只能在确定环境安全的内网中使用&#xff0c;不可在公网服务器设置&#xff0c;有极大安全风险&#xff01; 注意&#xff01;本文中开启docker远程连接的…...

Docker 安装 ClickHouse 教程

Docker 安装 ClickHouse 教程 创建目录 首先&#xff0c;创建必要的目录用于存放 ClickHouse 的配置、数据和日志文件。 mkdir -p /home/clickhouse/conf mkdir -p /home/clickhouse/data mkdir -p /home/clickhouse/log chmod -R 777 /home/clickhouse/conf chmod -R 777 /…...

过渡到内存安全语言:挑战和注意事项

开放源代码安全基金会 ( OpenSSF )总经理 Omkhar Arasaratnam 讨论了内存安全编程语言的演变及其为应对 C 和 C 等语言的局限性而出现的现象。 内存安全问题已存在五十多年&#xff0c;它要求程序员从内存管理任务中抽离出来。 Java、Rust、Python 和 JavaScript 等现代语言通…...

在Pycharm中安装Cv2

安装OpenCV&#xff1a; 在Terminal中&#xff0c;输入以下pip命令来安装OpenCV&#xff1a; pip install opencv-python pip install opencv-contrib-python 如果下载速度较慢&#xff0c;可以考虑使用国内的pip镜像源&#xff0c;如清华大学源&#xff1a; pip install openc…...

减少重复的请求之promise缓存池(构造器版) —— 缓存promise,多次promise等待并返回第一个promise的结果

减少重复的请求之promise缓存池 —— 缓存promise&#xff0c;多次promise等待并返回第一个promise的结果 背景简介 当一个业务组件初始化调用了接口&#xff0c;统一个页面多吃使用同一个组件&#xff0c;将会请求大量重复的接口 如果将promise当作一个普通的对象&#xff0…...

cdq+bitset处理高维偏序

高维偏序 CDQ分治 假设处理的区间为 [ l , r ] [l,r] [l,r] &#xff0c;CDQ分治的过程&#xff1a; 如果 l ≥ r l\geq r l≥r &#xff0c;返回。设区间中点为 m i d mid mid &#xff0c;递归处理 [ l , m i d ] [l,mid] [l,mid] 和 [ m i d 1 , r ] [mid1,r] [mid…...

敏捷开发和传统开发,你更适合哪种?

时间&#xff1a;2024年 10月 03日 作者&#xff1a;小蒋聊技术 邮箱&#xff1a;wei_wei10163.com 微信&#xff1a;wei_wei10 音频&#xff1a;喜马拉雅 大家好&#xff0c;欢迎来到“小蒋聊技术”&#xff0c;我是小蒋&#xff01;今天我们来聊聊两个开发模式的“对决”…...

python之with

with上下文管理是什么呢&#xff1f; 一般都是使用系统提供的一些with语句&#xff0c;列如我要去读取一些数据进行分析&#xff0c;就可以使用with open去读取某些数据&#xff0c;或者我要把一些图片给他保存到某些地方&#xff0c;可以用with给他写入。 上下午管理器with是…...

vue3 升级实战笔记

最近要将公司项目的移动端进行 vue3 的升级工作&#xff0c;就顺便记录下升级过程。 项目迁移的思路 我的想法是最小改动原则。 从 vue2.x 升级到 vue3&#xff0c;且使用 vue3 的 选项式 API。构建工具要从 vue-cli&#xff08;webpack&#xff09;升级到 vite。路由需要升级到…...

利用函数模块化代码实操 ← Python

【知识点】 ● 模块化可以使代码易于维护和调试&#xff0c;并且提高代码的重用性。 ● 函数可以用来减少冗余的代码并提高代码的可重用性。函数也可以用来模块化代码并提高程序的质量。 ● 在 Python 中&#xff0c;可以将函数的定义放在一个被称为模块的文件中,这种文件的后缀…...

Java高效编程(12):重写toString方法

解锁Python编程的无限可能&#xff1a;《奇妙的Python》带你漫游代码世界 尽管 Object 类提供了 toString 方法的默认实现&#xff0c;但它返回的字符串通常不是类的使用者想要看到的。默认返回的字符串格式是类名加上“”符号和哈希码的十六进制表示&#xff0c;例如 PhoneNu…...

谷歌给到的185个使用生成式AI的案例

很多公司从利用AI回答问题&#xff0c;进而使用AI进行预测&#xff0c;向使用生成式AI Agent转变。AI Agent的独特之处在于它们可以采取行动以实现特定目标&#xff0c;比如引导购物者找到合适的鞋子&#xff0c;帮助员工寻找合适的健康福利&#xff0c;或在护理人员交接班期间…...

程序员如何通过专业与软技能提升核心竞争力

一、引言  随着AIGC的兴起&#xff0c;AI辅助编程工具如chatgpt、midjourney、claude等接二连三地涌现&#xff0c;编程领域的变革正逐步深化。面对这一变革&#xff0c;程序员们对于未来工作的前景有着种种不同的担忧和期待。他们担心AI可能取代部分编程工作&#xff0c;同时…...

基于YOLOv8的智能植物监测机器人

摘要:针对传统的植物病害检测方法依赖专家的经验,耗时耗力,并且准确性受限于个人的水平等问题。文中提出无线通信模块采用HTTP协议来传输数据图片,采用SoC核心处理器实现了便携化,采用对射式红外避障传感器实现自动避障功能。以YOLOv8算法为控制核心,并添加注意力机制以提…...

2024年OpenAI DevDay发布实时 API、提示缓存等新功能

就在几天前&#xff0c;一些重要人物如前 CTO Mira Murati 离开了 OpenAI。因此&#xff0c;看到 Sam Altman 在 DevDay 上登台&#xff0c;讨论开发者的新产品&#xff0c;感觉有点奇怪。 随着公司内部的这些变化&#xff0c;你不禁会想&#xff1a;我们还应该信任他吗&#…...

Raspberry Pi3B+之安装bookworm+Rpanion系统

Raspberry Pi3B之安装bookwormRpanion系统 1. 源由2. 系统安装3. 系统安装3.1 烧录系统3.2 设备接线3.3 配置无线3.4 更新系统3.5 安装git3.6 克隆Rpanion3.7 安装Rpanion 4. 系统管理5. 附录问题1&#xff1a;error: externally-managed-environment问题2&#xff1a;bookworm…...

无人机专业除理论外,飞手执照、组装、调试实操技术详解

无人机专业的学习除了丰富的理论知识外&#xff0c;飞手执照的获取、无人机的组装与调试等实操技术也是至关重要的。以下是对这些方面的详细解析&#xff1a; 一、无人机飞手执照 1. 必要性 法规要求&#xff1a;根据《民用无人驾驶航空器系统驾驶员管理暂行规定》等相关法规…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...