首页 > 编程语言 >C++异步调用 future async promise packaged_task

C++异步调用 future async promise packaged_task

时间:2024-10-14 18:33:53浏览次数:8  
标签:std 异步 task packaged C++ future promise 线程

背景:

C++ 异步调用是现代 C++ 编程中的一种重要技术,它允许程序在等待某个任务完成时继续执行其他代码,从而提高程序的效率和响应性。

C++11 引入了 std::async、std::future 和 std::promise 等工具,使得异步编程变得更加方便和直观。以下是关于 C++ 异步调用的详细介绍,包括基本概念、使用方法和示例代码。

以下代码头文件为:

#include <iostream>
#include <future>
#include <thread>
#include <chrono>

std::future:

std::future 是一个类模板,提供了一种访问异步操作结果的机制。

主要成员函数包括 get、wait 和 wait_for,其中 get 用于获取异步操作的结果,如果结果还不可用,get 会阻塞当前线程,直到结果可用。

注意:

不能单独使用,一定要配合另外三个使用。

get只能被调用一次,多次调用会抛异常。

调用wait()后,仍然可以使用get()来获取结果。

wait_for():等待异步操作完成,等待指定的时间段。如果超时了,会返回timeout.

 

std::async:

std::async 是一个函数模板,用于启动异步任务。它返回一个 std::future 对象,可以用来获取异步任务的结果。

std::async 可以指定执行策略。例如 std::launch::async 表示在新线程中异步执行,std::launch::deferred 表示延迟执行,直到调用 std::future::get 或 std::future::wait 时才开始执行。

 代码:

int compute(int x) 
{
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
    return x * x;
}

int asyncTest()
{
    // 启动异步任务
    std::future<int> result = std::async(std::launch::async, compute, 5);
    // 继续执行其他代码
    std::cout << "Doing some other work..." << std::endl;
    // 获取异步任务的结果
    int value = result.get(); // 这里会等待。
    std::cout << "Result: " << value << std::endl;
    return 0;
}

 

std::promise:

std::promise 是一个类模板,用于在异步任务中设置结果值。std::promise 可以与 std::future 配合使用,通过 std::promise::set_value 设置结果值,然后通过 std::future::get 获取结果值。

如何理解:配合thread用的,用来获取另外一个线程的执行结果。

如图:1)启动线程B时,可以传一个菜篮子(就是promise)进去。2)当线程B干完活了,就可以往菜篮子放菜。3)线程A就能通过get获取菜篮子的菜了。

注意事项

1.  std::promise的生命周期:确保std::promise对象在std:: future对象需要它之前保持有效。一旦std::promise对象被销毁,任何尝试通过std:: future对象访问其结果的操作都将失败。

2.  线程安全:std::promise的set_value和set_exception方法是线程安全的,但你应该避免在多个线程中同时调用它们,因为这通常意味着你的设计存在问题。

3.  异常处理:当使用std::promise时,要特别注意异常处理。如果std::promise的set_exception方法没有被调用,但异步操作中确实发生了异常,那么这些异常将不会被捕获,并可能导致程序崩溃。

4.  性能考虑:虽然std::promise和std::future提供了强大的异步编程能力,但它们也引入了额外的开销。在性能敏感的应用程序中,要仔细考虑是否真的需要它们。

5.  std::move 的使用:在将std::promise对象传递给线程函数时,通常需要使用std::move来避免不必要的复制。这是因为std::promise对象通常包含非托管资源(如共享状态),复制它们可能是昂贵的或不必要的。

 代码:

void doWork(std::promise<int>&& p) {
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
    p.set_value(42); // 设置结果值
}

int promiseTest() 
{
    std::promise<int> prom;  // 创建 promise
    std::future<int> fut = prom.get_future();

    // 启动线程执行异步任务.  注意这里一定要用move进去,不能用拷贝构造。
    std::thread t(doWork, std::move(prom));

    // 继续执行其他代码
    std::cout << "Doing some other work..." << std::endl;

    // 获取异步任务的结果
    int value = fut.get();
    std::cout << "Result: " << value << std::endl;

    t.join();
    return 0;
}

 

std::packaged_task:

std::packaged_task 是一个类模板,包装了一个可调用对象(如普通函数、lambda 表达式、函数对象等),以便异步调用。它也可以与 std::future 配合使用,通过 std::packaged_task::get_future 获取 std::future 对象。

就是把一堆函数封装了一下,方便异步调用,适合用来做线程池,把不同的任务封装成统一的packaged_task,然后统一调度:参考:https://www.cnblogs.com/xcywt/p/18429228

启动流程:

 代码:

int computeTTT(int x) 
{
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
    return x * x;
}

int packaged_task_Test() {
    // 创建 packaged_task
    std::packaged_task<int(int)> task(computeTTT);  // 把一个函数包装一下。
    std::future<int> result = task.get_future();

    // 启动线程执行异步任务
    std::thread t(std::move(task), 5);

    // 继续执行其他代码
    std::cout << "Doing some other work..." << std::endl;

    // 获取异步任务的结果
    int value = result.get();
    std::cout << "Result: " << value << std::endl;

    t.join();
    return 0;
}

 

比较:

 

 

 

 

标签:std,异步,task,packaged,C++,future,promise,线程
From: https://www.cnblogs.com/xcywt/p/18464538

相关文章

  • 实验1 现代C++编程初体验
    任务11//现代C++标准库、算法库体验2//本例用到以下内容:3//1.字符串string,动态数组容器类vector、迭代器4//2.算法库:反转元素次序、旋转元素5//3.函数模板、const引用作为形参67#include<iostream>8#include<string>9#include......
  • 实验1 C++
    task1:1#include<iostream>2#include<string>3#include<vector>4#include<algorithm>56usingnamespacestd;78//声明9//模板函数声明10template<typenameT>11voidoutput(constT&c);1213//普通函数声明......
  • 【最新原创毕设】基于SpringCloud的一站式热点推荐平台+23649(免费领源码)可做计算机毕
    目 录摘要1绪论1.1选题背景与意义1.2开发现状1.3论文结构与章节安排2 开发环境及相关技术介绍2.1MySQL数据库2.2 Tomcat服务器2.3 Java语言2.4 SpringCloud框架介绍3 一站式热点推荐平台系统分析3.1可行性分析3.1.1技术可行性分析3.1......
  • (2024最新毕设合集)基于SpringBoot的通江银耳销售管理系统-15998|可做计算机毕业设计JAV
    摘要随着人们健康意识的增强,银耳这种传统的中药食材备受关注。而通江银耳是四川省通江县特产,中国国家地理标志产品。四川省通江县是银耳的发源地,中国银耳之乡,通江银耳因主产于此而得名,以其独到的质厚、肉嫩、易炖化和非常高的营养价值及药用价值而享誉海内外。需要一个高效便......
  • 实验1现代c++编程初体验
    1.实验任务一task1.cpp//现代C++标准库、算法库体验//本例用到以下内容://1.字符串string,动态数组容器类vector、迭代器//2.算法库:反转元素次序、旋转元素//3.函数模板、const引用作为形参#include<iostream>#include<string>#include<vector>#include<......
  • 实验4-2-3-for 验证“哥德巴赫猜想C++解法
    #include<iostream>#include<cmath>boolvia(longlongi);usingnamespacestd;intmain(){  longlongn=0,i=3,p=0,q=0,a=0,b=0;  cin>>n;  if(n>4)  {    for(i=3;i<n/2;i+=2)    {......
  • 螺旋方阵C++解法
    #include<iostream>#include<vector>usingnamespacestd;#include<iomanip>intn;intmain(){   cin>>n;   vector<vector<int>>arr(n,vector<int>(n,0));   intx=0,y=0,s=1;   while(s<=n*......
  • Qt/C++编写的mqtt调试助手使用说明
    一、使用说明第一步,选择协议前缀,可选mqtt://、mqtts://、ws://、wss://四种,带s结尾的是走ssl通信,ws表示走websocket通信。一般选默认的mqtt://就好。第二步,填写服务所在主机地址,可以是IP地址也可以是网址,只要真实存在的就行。第三步,填写通信所用端口号,mqtt默认端口号是1883,以......
  • C++可用的websocket库
    库说明优势劣势是否免费商用QtWebSocketsQt框架中的WebSocket模块。不需要额外集成第三方库;支持异步处理,适合在Qt应用程序中处理并发WebSocket请求。性能较差付费libwebsockets轻量级的C库,用于开发WebSocket服务器和客户端。高性能,低内存占用,支持多种平台,包......
  • 慧通教育C++测试题 103667--103673(5题)
    103667.求最大值难度:1登录//103667.求最大值难度:1#include<bits/stdc++.h>usingnamespacestd;intans=0,n,m,q,a[105][105];intmain(){ cin>>n>>m>>q; for(inti=1;i<=n;i++){ for(intj=1;j<=m;j++){ cin>>a[i][j]; } } int......