首页 > 其他分享 >`std::future`--异步的优势

`std::future`--异步的优势

时间:2024-10-07 12:00:44浏览次数:8  
标签:std 异步 -- 任务 future 线程 result

std::future 相比于直接使用线程在 C++ 中有几个重要的优势,主要体现在同步结果获取简化代码管理、以及更安全的异步任务管理等方面。以下是 std::future 的一些主要优势:

1. 自动结果获取与同步

  • std::future 提供了一种便捷的机制来获取异步任务的返回值。当我们使用线程时,通常无法轻松获得线程的返回值,线程函数如果有返回值,需要通过共享变量、全局变量或其他同步机制进行通信,这使得代码更加复杂。

  • 通过 std::future,可以轻松获取异步任务的结果,它在内部同步管理任务执行的结果。

    例子:

    #include <iostream>
    #include <future>
    
    int compute() {
        return 42;
    }
    
    int main() {
        std::future<int> result = std::async(std::launch::async, compute);
        std::cout << "Result: " << result.get() << std::endl; // 自动等待线程完成并返回结果
        return 0;
    }
    

    在这种情况下,result.get() 会等待线程完成,并获取异步任务的返回值 42。这比直接使用线程共享状态的方式要简单得多。

2. 简化代码管理

  • 使用 std::thread 需要手动管理线程的生命周期,比如使用 join() 来等待线程执行完成。而 std::future 通过 get() 或者 wait() 来等待任务完成,自动管理同步,不需要手动调用 join()

    直接使用线程时:

    #include <iostream>
    #include <thread>
    
    void compute(int &result) {
        result = 42;
    }
    
    int main() {
        int result;
        std::thread t(compute, std::ref(result));
        t.join(); // 必须手动调用 join() 等待线程完成
        std::cout << "Result: " << result << std::endl;
        return 0;
    }
    

    这里要通过 std::ref(result) 共享数据,并且必须手动管理线程的结束 (join()),否则程序会发生错误。

3. 更安全的异步任务管理

  • std::futurestd::async 可以更好地管理异步任务,避免直接操作线程带来的错误。比如,当线程没有被正确 join 时,程序可能崩溃,而 std::future 会自动等待异步任务完成。

  • 如果程序异常退出或者忘记调用 join()std::thread 会导致程序中断或者未定义行为。而 std::future 不会发生这些问题,它通过 get() 自动等待异步任务完成。

    例如,如果使用 std::thread,忘记 join(),程序会出现崩溃风险:

    std::thread t([] { std::this_thread::sleep_for(std::chrono::seconds(1)); });
    // 如果没有 t.join(),程序将崩溃
    

4. 异常管理

  • std::future 可以捕获异步任务中的异常,而直接使用线程时,异常管理需要额外的工作。在 std::future 中,get() 不仅可以获取任务的结果,还可以在任务中出现异常时,将该异常抛出,方便后续处理。

    例子:

    #include <iostream>
    #include <future>
    #include <stdexcept>
    
    int faulty_task() {
        throw std::runtime_error("Something went wrong!");
    }
    
    int main() {
        std::future<int> result = std::async(std::launch::async, faulty_task);
        try {
            int value = result.get(); // 在此捕获异常
        } catch (const std::exception& e) {
            std::cerr << "Exception: " << e.what() << std::endl;
        }
        return 0;
    }
    

    直接使用 std::thread 时,要处理任务中的异常需要复杂的机制,std::future 简化了这一过程。

5. 延迟启动任务

  • 使用 std::asyncstd::future,你可以选择是否立即启动线程,或者延迟执行任务(惰性启动)。通过 std::async 的第二个参数(如 std::launch::deferred),可以控制任务是否异步执行或延迟执行,这种灵活性在直接使用线程时无法轻易实现。

    惰性启动:

    std::future<int> result = std::async(std::launch::deferred, compute); // 任务并不会立即执行
    // result.get() 执行时,任务才开始执行
    

总结

std::future 的主要优势在于:

  • 简化了异步任务的结果获取与同步操作;
  • 提供了更好的异常管理;
  • 避免了手动管理线程生命周期的复杂性;
  • 提供了延迟执行(deferred execution)的灵活性。

相比之下,std::thread 直接操作线程,虽然可以让程序员显式控制任务,但在实际开发中,这种显式控制常常导致复杂的代码管理和更大的错误风险,因此 std::future 是一种更高层次、更安全的选择。

标签:std,异步,--,任务,future,线程,result
From: https://www.cnblogs.com/niumachen/p/18449881

相关文章

  • What is the difference between a Homemaker and a Housewife?
    Theterms"homemaker"and"housewife"areoftenusedinterchangeably,buttheycancarrydifferentconnotationsandimplications:HomemakerDefinition:Ahomemakerisgenerallysomeonewhomanagesahouseholdandtakescareofhome-re......
  • std::packaged_task<返回类型(参数类型)>
    std::packaged_task概述std::packaged_task是C++11引入的标准库模板类,用于包装一个可调用对象(如函数、lambda表达式、函数对象等),使其能够与std::future协同工作。简单来说,它将一个任务(可调用对象)包装起来,并允许你获取该任务的执行结果,这样你可以在一个线程中执行任务,并在......
  • whenever
      一、引导让步状语从句表示“无论何时”,相当于atwhatevertime,nomatterwhen等。例句:WheneverIseehim,he’sreading.我无论什么时候看到他,他都在看书。WheneverIgotoLondonItrytoseeVieky.我什么时候去伦敦,都设法去看看维基。二、......
  • std::make_shared
    std::make_shared是C++11引入的一个标准库函数,用于创建一个std::shared_ptr,并在堆上分配所需的对象。它的功能是将对象的创建和shared_ptr的初始化合并在一起,提高了效率和安全性。使用方法:autoptr=std::make_shared<T>(args...);T:共享指针所管理的对象的类型。a......
  • 张量矩阵乘法分块乘法概述
    张量矩阵乘法分块乘法概述介绍一下矩阵计算相关的内容,从最基本的算法,到Cutlass这些线性代数模版库,特别是Layout代数相关的内容,再逐渐细化到一些硬件实现访存优化和一些算子融合。6.3.1GEMM概述1.GEMM定义对于一个矩阵乘法,定义如下: (6-1)一个矩阵乘法定义,如图6-26......
  • Java与线程
    Java与线程1.线程的实现线程是比进程更轻量级的调度执行单位,线程的引人,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件IO等),又可以独立调度。目前线程是Java里面进行处理器资源调度的最基本单位。主流的操作系统都提供了线程实现,Java语言......
  • sql-labs靶场第四关测试报告
    目录一、测试环境1、系统环境2、使用工具/软件二、测试目的三、操作过程1、寻找注入点2、注入数据库①Orderby判断列数②判断回显地方③爆库,查看数据库名称④爆表,查看security库的所有表⑤爆列,查看users表的所有列⑥成功获取用户名和密码信息3、sqlmap注入方法......
  • sql-labs靶场第二关测试报告
    目录一、测试环境1、系统环境2、使用工具/软件二、测试目的三、操作过程1、寻找注入点2、注入数据库①Orderby判断列数②判断回显地方③爆库,查看数据库名称④爆表,查看security库的所有表⑤爆列,查看users表的所有列⑥成功获取用户名和密码信息3、sqlmap注入方法......
  • clang-format的代码格式化
    1.VSCodesettings.json{"C_Cpp.default.intelliSenseMode":"windows-msvc-x64",//"C_Cpp.clang_format_fallbackStyle":"Google","C_Cpp.clang_format_path":"D:/software/clang+llvm-18.1.8-x86_64-p......
  • c++指针传递与引用传递
    c不支持引用传递的!在C++中,指针传递和引用传递是两种常用的参数传递方式,它们各自有不同的特点和适用场景。下面是两者之间的主要区别:1.语法和使用指针传递定义和调用:函数参数是一个指针类型,调用时需要传递变量的地址。解引用:在函数内部需要使用解引用操作符*来访问指针......