C++ std::future与promise(异步回调异步调用)

Posted Dontla

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ std::future与promise(异步回调异步调用)相关的知识,希望对你有一定的参考价值。

文章目录

std::future

std::future<Ret>是一个C++标准库类,它表示一个异步操作的未来结果。它可以用来存储异步调用的结果。

案例1

// 下面是一个使用std::future<Ret> 的完整使用案例:

// 下面的代码使用std::packaged_task和std::future实现了异步回调函数AsyncCallback,其中Func为可调用对象,
// Arg为可调用对象f的参数列表,Ret为可调用对象f的返回类型。
// 首先,使用std::packaged_task封装可调用对象f,这样可以将一个普通函数转换为可调用对象,并且可以获取返回结果。
// 然后,使用std::future获取async函数的返回值,std::future是一个模板类,其模板参数Ret指定返回值的类型。
// 接着,将std::packaged_task实例task封装在std::thread中,并将参数arg传入线程中,当线程执行完毕之后,
// 通过future.get()获取返回结果,最后返回返回值。

// 为什么下面要用std::packaged_task而不用std::bind?
// 因为std::bind可以将一个普通函数或者可调用对象转换为可调用对象,但是它不能获取返回结果,而std::packaged_task则可以获取返回结果。
// 此外,std::packaged_task中的参数和返回类型都可以指定,而std::bind中的参数和返回类型无法指定。

#include <iostream> // 引入输入输出头文件
#include <future>   // 引入future头文件

int add(int a, int b) // 定义求和函数

    return a + b;


template <typename Func, typename Arg, typename Ret> // 定义泛型函数  //模板老编译不过不知道为什么。。。
Ret AsyncCallback(Func f, Arg arg)                   // 声明AsyncCallback函数

    std::packaged_task<Ret(Arg)> task(f);        // 创建一个std::packaged_task对象
    std::future<Ret> future = task.get_future(); // 获取函数的返回值
    std::thread t(std::move(task), arg);         // 创建线程执行函数
    t.join();                                    // 等待线程结束
    return future.get();                         // 返回函数的返回值


int main()

    std::cout << "Result of add is: " << AsyncCallback<decltype(&add), int, int>(add, 5, 10) << std::endl; // 调用AsyncCallback函数
    return 0;

编译运行:g++ test.cpp && ./a.out

编不过不知道为啥。。。

貌似模板没写对,改一下(不知为何在调用future.get()前必须显式join或detach子线程)

// 下面是一个使用std::future<Ret> 的完整使用案例
#include <iostream>
#include <future>
#include <chrono>

int add(int a, int b) // 定义求和函数

    std::this_thread::sleep_for (std::chrono::seconds(2));
    return a + b;


template <typename Ret, typename Func, typename ... Arg> 	// 定义泛型函数
Ret AsyncCallback(Func f, Arg ... arg)

    std::packaged_task<Ret(Arg ...)> task(f);        		// 创建一个std::packaged_task对象
    std::future<Ret> future = task.get_future(); 			// 获取函数的返回值

    std::cout << "thread start" << std::endl;
    std::thread t(std::move(task), arg ...);         		// 创建线程执行函数
    t.join();                                    			// 等待线程结束    //必须显示join或detach子线程,否则后面future.get就会报错,不知道什么原因
    //t.detach();

    //do something...
    std::cout << "do something..." << std::endl;
    std::this_thread::sleep_for (std::chrono::seconds(1));

    return future.get();


int main()

    int result = AsyncCallback<int>(add, 5, 10);			 // 调用AsyncCallback函数
    std::cout << "Result of add is: " << result << std::endl;
    return 0;

编译运行结果:

但是如果不join或detach:

不知道为什么非得显式join或detach,否则运行报错:terminate called without an active exception


貌似确实需要显式join或detach子线程,因为如果不那样做,线程对象在析构时将会检查线程对象状态,如果线程处于nonjoinable状态时,会调用terminate()函数直接令程序退出

参考文章:【C++】join()和detach|不join()也不detach()的后果

std::promise

std::future和std::promise结合使用

案例1

// linux C++使用Future和Promise实现一个线程对另一个线程的结果的传递和处理
#include <chrono>
#include <thread>
#include <future>
#include <iostream>

int compute(int x)

    return x * x;


int main()

    std::promise<int> result;
    std::thread t([&result](int x)
                
                    int res = compute(x);
                    //result.set_value(res);
                    std::this_thread::sleep_for(std::chrono::seconds(2));
                    std::cout << "set_value start" << std::endl;
                    result.set_value(res*res);  //只要本线程的promise执行set_value,另一个线程的future get就能立即得到
                    std::this_thread::sleep_for(std::chrono::seconds(2));
                    std::cout << "set_value end" << std::endl;
                , 10); // pass 10 to the thread

    std::cout << "get_future() start" << std::endl;
    auto future = result.get_future();  //获取future对象

    std::cout << "get() start" << std::endl;
    int value = future.get();   //阻塞
    std::cout << "Result is: " << value << '\\n';

    t.join();
    return 0;

编译运行结果:

C++什么情况下用future,什么情况下用promise,什么情况下两者都用,future和promise的的功能和作用是什么?

• Future:当我们想要获取一个异步运行的函数的结果时,可以使用Future。
• Promise:当我们想要将一个异步运行的函数的结果传递给另一个函数时,可以使用Promise。
• 两者都用:当我们想要需要一个线程实现对另一个线程的结果的传递和处理时,可以使用Future和Promise的结合来实现。
• Future的功能和作用:Future是一个异步运行的特殊类,它可以帮助我们在不阻塞程序流程的情况下,获取异步运行的函数的返回值。
• Promise的功能和作用:Promise是一个异步运行的特殊类,它可以帮助我们在不阻塞程序流程的情况下,将异步运行的函数的返回值传递到另一个函数中。

参考文章:c++11多线程编程同步——使用future和promise

以上是关于C++ std::future与promise(异步回调异步调用)的主要内容,如果未能解决你的问题,请参考以下文章

C++ std::future与promise(异步回调异步调用)

c++ 中的 std::promise 和 std::future

C++运行报错:what(): std::future_error: Broken promise

C++运行报错:what(): std::future_error: Broken promise

C++并发学习笔记

folly教程系列之:future/promise