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

async,future,packaged_task,promise

一.std::async,std::future创建后台任务并返回值

原来通过thread对象创建一个线程,用成员函数join()等待程序完成,现在希望线程返回一个结果,可以把线程的结果赋给一个变量,有一个更好的办法:std::async

相关概念

std::async是一个类模板,用来启动一个异步任务之后它返回一个std::future的对象,std::future是一个类模板

  • 启动异步任务:自动创建一个线程并开始执行对应的线程入口函数,返回一个std::future的对象
  • 这个std:future的对象里面就有线程入口函数所返回的结果。可以通过调用future对象成员函数get()来获取结果。一个future对象只能调用一次get()。
  • future的另外一个成员函数wait()会等待线程返回但本身不返回结果
语法
1.普通函数
std::future<数据类型> result(future对象名,这里假设为result)=std::async(入口函数名); std::cout<<result.get()<<std::endl; //输出入口函数返回的结果,线程会卡在get()这里等待入口函数执行完毕拿到返回值 //result.wait(); //等待线程返回,本身不返回结果 //不用get()或者wait()不报错但仍然会等待线程执行完毕
2.成员函数
std::future<数据类型> result=std::async(&类名,&类对象名,传入参数); std::cout<<result.get()<<std::endl;
3.通过额外向std::async()传递一个参数,该参数类型是std::lunnch类型(枚举类型),来达到一些特殊的目的;
  1. std::launch::deferred
    表示线程入口函数调用被延迟到std::future的wait或者get函数调用时才执行,不会创建新线程而是在主线程中调用入口函数
    std::future<数据类型> result=std::async(launch::deferred,入口函数名); std::cout<<result.get()<<std::endl;
  2. std::launch::async(默认标记)
    在调用async函数的时候就开始创建线程

示例

#include<iostream> #include<thread> #include<list> #include<mutex> #include<future> #include<map> using namespace std; class A { public: int print(int val) { cout << "线程print开始,id= " << this_thread::get_id() << endl; this_thread::sleep_for(chrono::seconds(1)); //休息5秒 cout << "线程print结束,id= " << this_thread::get_id() << endl; return val; //返回值 } }; int print1() { cout << "线程print1开始,id= " << this_thread::get_id() << endl; this_thread::sleep_for(chrono::seconds(1)); //休息5秒 cout << "线程print1结束,id= " << this_thread::get_id() << endl; return 5; //返回值 } int main() { cout << "主线程开始,id= " << this_thread::get_id() << endl; future<int> result = async(print1); cout << result.get() << endl; //卡在这里等待print函数执行完拿到返回值 A a; int val = 10; future<int> result2 = async(&A::print,&a,val); cout << result2.get() << endl; std::cout << "主线程结束" << std::endl; return 0; }

二.std::packaged_task

是一个类模板,模板参数是各种可调用对象。

作用

通过std::packaged_task把各种可调用对象包装起来,方便作为线程入口函数调用。

语法
std::packaged_task<函数类型(传入函数的参数类型)> 对象名1(入口函数); std::thread 对象名2(std::ref(对象名1),传入的参数); 对象名2.join(); std::future<数据类型>result=对象名1.get_future(); std::cout<<result.get()<<std::endl; //成员函数get_future()保存的是被包装的入口函数返回的值 //或(示例lambda表达式) std::packaged_task<int(int)> p([](int val{函数定义})); int a; p(a); //相当于函数调用没有创建线程 std::future<int>result=p.get_future(); std::cout<<result.get()<<std::endl; //示例:存入容器和取用 vector<std::packaged_task<<int(int)>> v; //容器 v.push_back(std::move(p)); //移动语义,移动后p为空 auto it=v.begin(); packaged_task<int(int)> p2; //接收容器中的对象 p2=std::move(*it);

std::packaged_task是一个仅移动类型(move-only),它没有拷贝构造函数,只有移动构造函数。
如果不用std::ref,编译器会尝试拷贝p,导致编译错误;

#include<iostream> #include<thread> #include<list> #include<mutex> #include<future> #include<map> #include<vector> using namespace std; int print1(int val) { cout << "线程print1开始,id= " << this_thread::get_id() << endl; this_thread::sleep_for(chrono::seconds(1)); //休息5秒 cout << "线程print1结束,id= " << this_thread::get_id() << endl; return val; //返回值 } int main() { cout << "主线程开始,id= " << this_thread::get_id() << endl; packaged_task<int(int)> p(print1); thread t1(ref(p), 1); t1.join(); future<int>result = p.get_future(); //成员函数get_future()保存的是p里面的被包装的入口函数返回的值 cout << result.get() << endl; packaged_task<int(int)> p1([](int val) { cout << "线程print1开始,id= " << this_thread::get_id() << endl; this_thread::sleep_for(chrono::seconds(1)); //休息5秒 cout << "线程print1结束,id= " << this_thread::get_id() << endl; return val; //返回值 }); p1(6); vector<packaged_task < int(int) >> v; //容器 v.push_back(std::move(p1)); //移动语义,移动后p1为空 auto it = v.begin(); packaged_task<int(int)> p2; //接收容器中的对象 p2 = std::move(*it); v.erase(it); future<int>result1 = p2.get_future(); cout << result1.get() << endl; std::cout << "主线程结束" << std::endl; return 0; }

三.std::promise

作用

在某个线程中给它赋值,然后可以再其他线程中,把这个值取出来用:

语法
//函数示例 void cal(std::promise<int>&temp,int a) { a*=100; temp.set_value(a); //将计算结果存入temp对象 } void thread1(std::future<int>& temp) { auto result = temp.get(); std::cout << result << std::endl; } int main() { std::promise<int> mp; //声明一个promise对象 thread t(cal,std::ref(mp),10); t.join(); std::future<int>f=mp.get_future(); thread t2(thread1, std::ref(f)); //将结果传入t2 t2.join(); cout<<"主线程结束"<<std::endl; return 0; }
http://www.jsqmd.com/news/668856/

相关文章:

  • 从毛玻璃到沉浸式界面:探索CSS filter与backdrop-filter的进阶应用
  • 别再只会用‘w‘和‘r‘了!Matlab fopen函数权限参数全解析(含编码与字节序)
  • 项目实训博客2 刻画能力画像:动态用户与岗位画像建模
  • 怎样设计一块独特的牌匾?
  • 深度空间装饰回头客多
  • Notion 白屏故障排查:从客户端到浏览器的全方位修复指南
  • 手机无限重启怎么办
  • [MYSQL/K8s] 基于 Kubenetes 集群安装 MYSQL
  • 实战指南|3类高频软件漏洞,从识别到修复一步到位
  • 7岁、10岁、14岁开始学C++,收益与必要性有何不同?
  • Spring Boot 条件装配入门:一文搞懂 @ConditionalOnClass(附实战)
  • 2026年泰迪杯A完整题解方案-详细解题思路和论文+完整项目代码+全套资源
  • C语言之Redis源码阅读学习顺序
  • 2026市场岗位学数据分析的价值分析
  • Windows (PowerShell)安装部署OpenClaw
  • 从CTFHub靶场实战出发:手把手教你用Gopher协议打穿SSRF(附BurpSuite配置)
  • 瓶子倒水二分法:最大化最小值
  • 下篇:Python 多任务编程入门(二)—— 进程同步、进程池与注意事项
  • leetcode热题 - 3
  • 力扣-142.环形指针
  • Delphi 10.4.2 实战:手把手教你用FMXLinux在Ubuntu上跑通第一个GUI程序
  • 从kHz到EHz:揭秘频率单位阶梯的换算逻辑与工程应用场景
  • Django 后台导出数据功能的实现
  • Gemini出点问题-----解决
  • 手写一个最小 Starter:从 0 到能看懂
  • 考研复习Day 16 | 数据结构与算法 --树与二叉树(上)
  • AI Agent Harness Engineering 的部署架构:单体部署、分布式部署与混合云
  • 终极BT下载加速指南:每天更新的Tracker列表让你的下载速度翻倍
  • FastAPI 项目 PyInstaller 打包 exe 全踩坑根治教程(Windows 全电脑通用分发)
  • 企业云盘选型标准合同条款:数据归属/服务等级/SLA全解析