news 2026/4/20 1:37:48

async,future,packaged_task,promise

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 1:31:15

计算机毕业设计:Python农业电商销售数据分析平台 Django框架 数据分析 可视化 大数据 大模型 机器学习(建议收藏)✅

博主介绍&#xff1a;✌全网粉丝50W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业项目实战8年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ > &#x1f345;想要获取完整文章或者源码&#xff0c;或者代做&#xff0c;拉到文章底部即可与…

作者头像 李华
网站建设 2026/4/20 1:26:27

罗茨风机行业专题研究:出口中东罗茨风机国际认证、质量达标的品牌

随着我国工业现代化进程加速及环保政策趋严&#xff0c;罗茨风机作为污水处理、电力、化工等领域的关键设备&#xff0c;市场需求持续增长。据中国通用机械工业协会统计&#xff0c;2024年我国罗茨风机市场规模达82.3亿元&#xff0c;年复合增长率7.5%&#xff0c;行业呈现技术…

作者头像 李华
网站建设 2026/4/20 1:24:57

mysql如何优化索引以减少扫描_mysql高效索引设计原则

MySQL索引失效主因是最左前缀原则被破坏&#xff1a;范围查询或跳过中间列会导致右侧列无法使用索引&#xff1b;ORDER BY需满足最左连续列且排序方向一致&#xff1b;索引过多拖慢写入&#xff0c;应评估选择性与实际使用率&#xff1b;EXPLAIN中key_len和Extra比type更能反映…

作者头像 李华
网站建设 2026/4/20 1:15:01

【Linux】NFS 实践手册 - Ubuntu 系统

NFS 实践手册 - Ubuntu 系统 1. 环境准备 1.1 系统要求 Ubuntu 服务器版/桌面版 18.04 或更高版本局域网内所有设备处于同一网络段了解服务器IP地址&#xff08;可通过 ip addr 或 ifconfig 查看&#xff09; 2. NFS 服务器端配置 2.1 安装 NFS 服务器 # 更新包列表 sudo apt u…

作者头像 李华