C++11标准 future异步线程库

原文链接:C++11标准 future异步线程库

前言

c++标准有很多的版本,比较知名的如c++98是第一版c++标准,提供了c++最底层的支持. 后面的c++11和c++20每个版本都会给c++带来新特性.

而线程就是是c++11最重要的特性.

虽然c++98有pthread库,但是c++11的thread有更好的跨平台能力,最重要的是c++11很多线程特性都是在thread库基础上实现的.

例如本节的异步线程future库,以及其他的如信号量,智能指针,functional函数封装,万能模板,完美转发等等.

这些特性为c++提供了原生线程支持.

thread实现 普通的异步线程

主线程创建一个线程执行操作,在这个过程中子线程和主线程并发执行.

如果该线程需要返回一个计算结果,此时可以通过传入变量的引用传参或全局变量实现.例如

#include <iostream>
#include <thread>
#include <chrono>// 异步任务函数
void asyncTask(int& a) {std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时操作a+=1; 
}int main() {int a = 5; std::cout << "Main thread is starting...\n";std::thread t1(asyncTask, std::ref(a));std::cout << "Main thread is doing other work...\n";if (t1.joinable()) {t1.join();}std::cout << "Result from thread: " << a << "\n"; std::cout << "Main thread is completed.\n";return 0;
}

主线程通过引用参数,可以获取计算结果

如果主线程和子线程执行过程中都要操作同一个对象,那就还需要信号量实现 临界区操作的线程同步

future的作用

c++11 库主要提供了4种不同层次的对象,分别适用不同应用场景.

std::future: future可以表示一个线程返回的结果,.get() 会阻塞直到异步操作完成,还有其他的一些特性
std::promise: future可以绑定promise,可以在一个线程中通过promise设置值,然后在另一个线程中使用future获取这个值
std::async: 线程的高阶封装,async会自动创建线程执行操作,并且返回future对象获取结果
std::packaged_task: 相比async更加灵活,可以将一个任务封装成 packaged_task对象,显式调用thread执行.

packaged_task是实现线程池的关键对象,可以保证线程的重复利用,而不是每个任务就新创建线程

还有一些其他的对象:
std::shared_future

future

函数
//模板类型
template< class T > class future;
template< class T > class future<T&>;
template<> class future<void>;T/T&/void get(); 一直阻塞直到返回对象值//对象是否有效
bool valid() const noexcept; 当future对象未绑定对象或者对象已经获取过了,返回false return true(有效) false(无效)//3 种wait函数 //阻塞到获得返回值
void wait() const;
//阻塞一定时间
template< class Rep, class Period >
std::future_status wait_for( const std::chrono::duration<Rep,Period>& timeout_duration ) const;
//阻塞到设定时间点
template< class Clock, class Duration >
std::future_status wait_until( const std::chrono::time_point<Clock,Duration>& timeout_time ) const;std::future_status有3种状态:future_status::ready  准备好了future_status::timeout	超时future_status::deferred	std::async通过参数std::launch::deferred创建一个延迟执行的异步线程,该状态表示程序还未开始执行,当调用get或wait才开始执行
特性
  1. future本身无法单独使用,要结合promise或async才能绑定对象
  2. future只能移动构造,不能复制

promise

函数
//模板类型
template< class R > class promise;
template< class R > class promise<R&>;
template<> class promise<void>;//获取future
std::future<R> get_future();该返回的对象是promise唯一关联的future对象,不能复制,只能移动return future对象//设置值,可以传入右值引用,引用,常引用 
设置完毕后future此时变为ready
void set_value( const R& value );
void set_value( R&& value );
void set_value( R& value );延迟设置,当线程结束时才设置,参数同set_value
void set_value_at_thread_exit(const R&/R&&/R& value);
特性
  1. promise与future是唯一对应的
示例:子线程等一秒返回数据,主线程get等待
#include<future>
#include<thread>
#include<iostream>
#include<chrono>int main(){std::promise<int> p;std::future<int> f=p.get_future();std::thread t([](std::promise<int>& p){std::this_thread::sleep_for(std::chrono::milliseconds(1000));p.set_value(1024);},std::ref(p));std::cout<<f.get()<<"\n";return 0;
}
示例:子线程等一秒返回数据,主线程wait_for等待
#include<future>
#include<thread>
#include<iostream>
#include<chrono>int main(){std::promise<int> p;std::future<int> f=p.get_future();std::thread t([](std::promise<int>& p){std::this_thread::sleep_for(std::chrono::milliseconds(1000));p.set_value(1024);},std::ref(p));t.detach();while(f.valid()){std::future_status status=f.wait_for(std::chrono::duration<int,std::milli>(500));if(status==std::future_status::ready){std::cout<<"get value="<<f.get()<<"\n";}else if(status==std::future_status::timeout){std::cout<<"time out\n";}}return 0;
}

输出:

time out
get value=1024
terminate called without an active exception

不加detach时发现程序出错了,主线程退出时子线程未结束

有两种方法,1是detach脱离主线程,2是join等待

在异步多线程里面一般是脱离主线程处理

async

函数
//不指定策略
template< class F, class... Args >
std::future async( F&& f, Args&&... args );
//指定策略
template< class F, class... Args >
std::future async( std::launch policy, F&& f, Args&&... args );policy有3async(立即执行) deferred(延迟执行) any(自动选择)
特性

特点:

  1. deferred会使线程延迟到当future被wait或get调用时才执行. deferred的线程如果一直没执行的话,一定程度上能降低负载.
  2. deferred策略不能和wait_for搭配使用,会导致线程一直不执行
  3. async+future能大幅度减少线程的代码量

优点:
简单,API直接使用,提高异步线程开发效率

缺点:
async会隐式创建线程,会增大程序性能开销

示例:deferred+wait_for 程序死锁
#include<future>
#include<thread>
#include<iostream>
#include<chrono>int main(){std::future<int> f=std::async(std::launch::deferred,[](int a){std::this_thread::sleep_for(std::chrono::milliseconds(1000));return a+1;},1023);while(f.valid()){std::future_status status=f.wait_for(std::chrono::duration<int,std::milli>(500));if(status==std::future_status::ready){std::cout<<"get value="<<f.get()<<"\n";}else if(status==std::future_status::timeout){std::cout<<"time out\n";}}return 0;
}

packaged_task:和future一样只能移动构造

函数
//packaged_task构造,R是返回类型, ArgTypes...是函数的参数类型
template< class R, class ...ArgTypes >
class packaged_task<R(ArgTypes...)>;  //交换两个任务
void swap( packaged_task& other ) noexcept;// 验证共享对象是否有效
bool valid()return true(future对象有效) false(无效)// 返回future对象
std::future<R> get_future();// 同promise中,当线程结束时才设置future
void make_ready_at_thread_exit();// 重置task状态,允许任务未执行前重新获取future对象
void reset();
特性

packaged_task最大特点是可用结合wrapper实现无参封装,同时不会自动创建线程.

示例1:packaged_task创建任务并通过thread执行

注意packaged_task在传给线程的时候必须move修饰为一个右值(将亡值),因为不可复制构造

#include<iostream>
#include<future>
#include<thread>
#include<chrono>
#include<unistd.h>
int main(){//定义taskstd::packaged_task<int(int)> task([=](int a){return a+1;});//定义两个返回值,先get future一次,此时的task 已经和ret1绑定std::future<int> ret1,ret2;ret1=task.get_future();//在任务未开始前重置task 和ret2绑定task.reset();ret2=task.get_future();std::thread t(std::move(task),1023);t.detach();std::cout<<ret2.get()<<"\n";return 0;
}
示例2: 使用packaged_task+function封装,实现一个简单的线程池

参考: C++实现一个线程池

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

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

相关文章

神经网络构建与训练深度学习模型全过程(PyTorch TensorFlow)

神经网络构建与训练深度学习模型全过程&#xff08;PyTorch & TensorFlow&#xff09; 目录 &#x1f517; 什么是神经网络&#xff1a;基础架构与工作原理&#x1f9e9; 构建简单的神经网络&#xff1a;层次结构与激活函数&#x1f680; 前向传播&#xff1a;神经网络的…

基于Handsontable.js + Excel.js实现表格预览和导出功能(公式渲染)

本文记录在html中基于Handsontable.js Excel.js实现表格预览、导出、带公式单元格渲染功能&#xff0c;在这里我们在html中实现&#xff0c;当然也可以在vue、react等框架中使用npm下载导入依赖文件。 Handsontable官方文档 一、开发前的准备引入相关依赖库 <!DOCTYPE ht…

微服务经典应用架构图

从网上找了一个经典的微服务架构图&#xff0c;资料来源于若依开源系统的ruoyi-cloud&#xff0c;仅供参考&#xff01;

面向城市运行“一网统管”的实景三维示范应用

在新型智慧城市建设的浪潮中&#xff0c;实景三维技术正成为推动城市治理现代化的重要力量。“一网统管”作为城市运行管理的新理念&#xff0c;强调了跨部门协作和数据共享&#xff0c;而实景三维技术为此提供了强有力的支撑。本文将探讨实景三维技术如何赋能“一网统管”&…

Linux笔记---vim的使用

1. vim的基本概念 Vim是一款功能强大的文本编辑器&#xff0c;它起源于Unix系统的vi编辑器&#xff0c;并在其基础上进行了许多改进和增强。 Vim以其高效的键盘操作、高度的可定制性和强大的文本处理能力而闻名&#xff0c;尤其受程序员和系统管理员的欢迎。 Vim支持多种模式…

cmake 编译 01

CMakeLists.txt cmake_minimum_required(VERSION 3.10)project(MyProject)set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True)# 如果顶层 CMakeLists.txt 文件中使用了 add_subdirectory() 命令&#xff0c;CMake 会进入指定的子目录&#xff0c;并处理该目录…

2024年超好用的防泄密软件分享|10款加密防泄密软件推荐

在当今数字化时代&#xff0c;企业数据安全已成为不可忽视的重要议题。随着数据泄露事件频发&#xff0c;选择一款高效可靠的防泄密软件变得尤为重要。本文将为您推荐10款在2024年备受推崇的防泄密软件&#xff0c;并重点介绍Ping32防泄密软件的功能与优势。 1. Ping32防泄密软…

Zico 2 靶机 - 详细流程

✨ 准备工作 靶机 && kali 环境要求 机器名网络配置靶机Zico 2NAT 模式攻击机kaliNAT 模式 靶机下载链接&#xff1a;zico2: 1 ~ VulnHub 打开 VMware&#xff0c;将 zico2.ova 拖拽到 VMware 中 设置 虚拟机名称(A) - 存储路径(P)- 导入 若是&#xff0c;…

3. 单例模式唯一性问题—构造函数

1. 构造函数带来的唯一性问题指什么&#xff1f; 对于不继承MonoBehaviour的单例模式基类 我们要避免在外部 new 单例模式类对象 例如 &#xff08;完整单例模式定义在上一节&#xff09; public class Main : MonoBehaviour {void Start(){// 破坏单例模式的唯一性&#xf…

【Python】AI Navigator对话流式输出

前言 在上一章节,我们讲解了如何使用Anaconda AI Navigator软件结合python搭建本机的大模型环境 【python】AI Navigator的使用及搭建本机大模型_anaconda ai navigator-CSDN博客 但是在上一章节搭建的大模型环境无法流式输出,导致输出需要等待很久,所以在这一章节,解决…

使用Three.js和Force-Directed Graph实现3D知识图谱可视化

先看样式&#xff1a; 在当今信息爆炸的时代&#xff0c;如何有效地组织和展示复杂的知识结构成为一个重要的挑战。3D知识图谱可视化是一种直观、交互性强的方式来呈现知识之间的关系。本文将详细介绍如何使用HTML、JavaScript、Three.js和Force-Directed Graph库来实现一个交互…

【深度学习】阿里云GPU服务器免费试用3月

【深度学习】阿里云GPU服务器免费试用3月 1.活动页面2.选择交互式建模PAI-DSW3.开通 PAI 并创建默认工作空间4.前往默认工作空间5.创建交互式建模&#xff08;DSW&#xff09;实例 1.活动页面 阿里云免费使用活动页面 2.选择交互式建模PAI-DSW 支持抵扣PAI-DSW入门机型计算用量…

【Unity新闻】Unity 6 正式版发布

Unity CEO Matt Bromberg 在今天自豪地宣布&#xff0c;Unity 6 正式发布&#xff01;作为迄今为止最强大和稳定的版本&#xff0c;Unity 6 为游戏和应用开发者提供了大量的新功能和工具&#xff0c;帮助他们加速开发并提升性能。 本次正式版是6.0000.0.23f1&#xff08;LTS&a…

spring-boot学习(2)

上次学习截止到拦截器 1.构建RESfun服务 PathVariable通过url路径获取url传递过来的信息 2.MyBatisPlus 第三行的mydb要改为自己的数据库名 第四&#xff0c;五行的账号密码改成自己的 MaooerScan告诉项目自己的这个MyBatisPlus是使用在哪里的&#xff0c;包名 实体类的定义…

AGI 之 【Dify】 之 使用 Docker 在 Windows 端本地部署 Dify 大语言模型(LLM)应用开发平台

AGI 之 【Dify】 之 使用 Docker 在 Windows 端本地部署 Dify 大语言模型&#xff08;LLM&#xff09;应用开发平台 目录 AGI 之 【Dify】 之 使用 Docker 在 Windows 端本地部署 Dify 大语言模型&#xff08;LLM&#xff09;应用开发平台 一、简单介绍 二、Docker 下载安…

设置 Notepad++ 制表符(Tab 缩进)宽度为2个空格大小

Notepad 默认的制表符宽度是 4 个空格的大小&#xff0c;一个规模比较大的代码段或者 xml 等文件&#xff0c;小屏幕打开时看到的情景真的和让人着急&#xff0c;拖来拖去&#xff01;有两种方案可以解决这种情况。 修改缩进为空格 这种我们不太推荐&#xff0c;但是有些公司…

小白必看web专题!配置环境还在用phpstudy?该用docker了!(php+nginx+mysql+phpmyadmin。)

大家好&#xff0c;我是Dest1ny。 大家用mac或者是windows都是使用phpstudy。 今天docker来搭建一整个phpnginxmysqlphpmyadmin。 而且mac用docker比较方便&#xff01; docker才是众望所归。 大家多多点赞&#xff0c;多多支持&#xff0c;谢谢&#xff01;&#xff01;&…

Qml-Item的构造和显示顺序

Qml-Item的构造和显示顺序 qml文件中组件构造顺序 在同一个qml文件中&#xff0c;同层级的Item, 文件尾的Item优先构造&#xff0c;文件首的Item后构造。这就能解释默认情况下同一个qml文件中&#xff0c;几个同层级的item都设置了focus:true&#xff0c;为啥最上面item最终有…

echarts设置x轴中文垂直显示,x轴滚动条

echarts官网配置&#xff0c;主要配置dataZoom option {xAxis: {type: category,data: [张三,李四,王五,赵六,孙七,周八,吴九,郑十,钱十一,陈十二,刘十三,杨十四,黄十五,何十六,宋十七],axisLabel: {formatter: function (value) {return value.split().join(\n); // 使用换行…