C++运行报错:terminate called after throwing an instance of ‘std::future_error‘(promise对象调用set前不能销毁!)

Posted Dontla

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++运行报错:terminate called after throwing an instance of ‘std::future_error‘(promise对象调用set前不能销毁!)相关的知识,希望对你有一定的参考价值。

文章目录

运行时报错信息

root@ubuntu:/userdata/20230201_test_cw_callback# ./a.out 
Waiting for the greeting...
terminate called after throwing an instance of 'std::future_error'
  what():  std::future_error: Broken promise
Aborted (core dumped)
root@ubuntu:/userdata/20230201_test_cw_callback# 

错误代码

/*
    这段代码实现了一个通过async_task函数执行线程中的函数,并通过std::promise对象将结果传递回主线程,最后使用std::future对象处理返回值。
*/

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

template <typename Func, typename... Arg>
auto async_task(Func &&f, Arg &&...arg)

    // 定义一个promise用于传递返回值
    std::promise<decltype(f(arg...))> promise;
    // 获取关联的future对象
    auto future = promise.get_future();
    // 创建线程
    std::thread t([&promise, &f, &arg...]()
                    
                        std::this_thread::sleep_for(std::chrono::seconds(2));
                        // 在线程中调用函数,并将返回值存储在promise中
                        promise.set_value(f(arg...)); 
                    );

    //std::cout << future.get() << std::endl;

    // 让主线程对线程进行管理
    t.detach();
    // 返回future对象
    return future;


std::string get_greeting(std::string name)

    return "Hello, " + name + "!";


int main()

    auto greeting_future = async_task(get_greeting, "ChatGPT");
    std::cout << "Waiting for the greeting..." << std::endl;
    std::cout << greeting_future.get() << std::endl;
    return 0;


/*
...的意思是可变参数,可以接受0个或多个参数。
&&的意思是引用折叠,表示函数可以接受任何类型的参数,如可以是左值也可以是右值。

写在arg前面表示函数能接受不定量的参数,而写在arg后面表示函数有一个可变参数,但是这个参数只能接受一个值。
*/

报错原因

不能用detach,因为async_task函数退出后,promise对象就被销毁了,销毁的对象去调用set_value,就会报Broken promise的错误,所以必须等待线程结束后,本函数再返回

解决办法

1、将上面代码中的detach改成join(但是这样做违背了异步回调的初衷)

/*
    这段代码实现了一个通过async_task函数执行线程中的函数,并通过std::promise对象将结果传递回主线程,最后使用std::future对象处理返回值。
*/

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

template <typename Func, typename... Arg>
auto async_task(Func &&f, Arg &&...arg)

    // 定义一个promise用于传递返回值
    std::promise<decltype(f(arg...))> promise;
    // 获取关联的future对象
    auto future = promise.get_future();
    // 创建线程
    std::thread t([&promise, &f, &arg...]()
                    
                        std::this_thread::sleep_for(std::chrono::seconds(2));
                        // 在线程中调用函数,并将返回值存储在promise中
                        promise.set_value(f(arg...)); 
                    );

    //std::cout << future.get() << std::endl;

    // 让主线程对线程进行管理
    //t.detach();   //不能用detach,因为本函数退出后,promise对象就被销毁了,销毁的对象去调用set_value,就会报Broken promise的错误,所以必须等待线程结束后,本函数再返回
    t.join();
    // 返回future对象
    return future;


std::string get_greeting(std::string name)

    return "Hello, " + name + "!";


int main()

    auto greeting_future = async_task(get_greeting, "ChatGPT");
    std::cout << "Waiting for the greeting..." << std::endl;
    std::cout << greeting_future.get() << std::endl;
    return 0;


/*
...的意思是可变参数,可以接受0个或多个参数。
&&的意思是引用折叠,表示函数可以接受任何类型的参数,如可以是左值也可以是右值。

写在arg前面表示函数能接受不定量的参数,而写在arg后面表示函数有一个可变参数,但是这个参数只能接受一个值。
*/

编译运行:

2、可以继续用detach(),但是需要用future.get()阻塞AsyncCallback函数返回

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

int add(int a, int b)

    return a + b;


template <typename Func, typename ...Arg>
auto AsyncCallback(Func&& f, Arg&& ...arg)

    std::promise<int> promise;
    std::future<int> future = promise.get_future();
    std::thread t([&]()
        int result = f(arg...);
        promise.set_value(result);
    );
    //t.join();
    t.detach(); //join和detach都可以,因为后面get()是阻塞的

	//do something...
	std::cout << "sleep_for(std::chrono::seconds(2))" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
    
    return future.get();


int main()

	int result = AsyncCallback(add, 5, 10);
    std::cout << "Result of add is: " << result << std::endl;
    return 0;


编译运行结果:

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

以上是关于C++运行报错:terminate called after throwing an instance of ‘std::future_error‘(promise对象调用set前不能销毁!)的主要内容,如果未能解决你的问题,请参考以下文章

C++11多线程运行报错:terminate called without an active exception(没有join或detach子线程)

C++11多线程运行报错:terminate called without an active exception(没有join或detach子线程)

gcc报错:terminate called after throwing an instance of ‘std::regex_error‘ what(): regex

gcc报错:terminate called after throwing an instance of ‘std::regex_error‘ what(): regex

gcc报错:terminate called after throwing an instance of ‘std::regex_error‘ what(): regex

gcc报错:terminate called after throwing an instance of ‘std::regex_error‘ what(): regex