std::future期望值的三处用法,以及向std::promise承诺值传入异常的用法

本文介绍了C++中std::future的三种使用方式,包括与std::promise、std::packaged_task和std::async的配合,以及如何处理异常。在std::promise中设置异常,通过std::future的get()方法会在消费者线程中重新抛出异常。同样,std::packaged_task和std::async中的异常也会传递给std::future,确保异常在适当线程中被捕获。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、std::future期望值的三处用法:

1、期望值std::future<T>与承诺值std::promise<T>搭配使用,执行"std::future<T> fu=pro.get_future();"绑定承诺值与期望值,承诺值pro.set_value()或pro.set_exception()传值后,由期望值fu.get()提取,或fu.wait()阻塞消费者线程直到期望值就绪;

2、期望值std::future<T>与打包任务std::packaged_task(func,args)搭配使用,执行"task.get_future()"绑定期望值与任务;任务入口函数执行完毕后,返回值返回给期望值,由期望值fu.get()提取,或fu.wait()阻塞消费者线程直到期望值就绪;

3、期望值std::future<T>与异步任务std::async()搭配使用,执行"std::future<T> fu=std::async(func,args)"绑定期望值与异步任务。异步任务入口函数执行完毕后,返回值返回给期望值,由期望值fu.get()提取,或fu.wait()阻塞消费者线程直到期望值就绪;

二、将异常存于期望值中——《C Concurrency in Actino 2》-4.2.4

对应上面三种用法:

1、当向承诺值std::promise<T>存入的是一个异常而非一个数值时,需要调用std::promise<T>::set_exception()成员方法,而非set_value()。这通常是用在一个try{}catch(){}块中,并作为算法的一部分。向承诺值写入一个异常的代码参考:

    i、std::current_exception()函数引用上文作用域抛出的异常;

    ii、承诺值写入的异常将在期望值试图get()提取时在期望值所在的消费者线程中抛出

#include<iostream>
#include<future>
#include<chrono>
#include<functional>
#include<exception>

using  F=std::function<int(int,int,int&)>;
//等同于typedef std::function<int(int,int,int&)>;
int Test_func(int a,int b,int &c){
    c=a+b;
    return c;
};
void Productor(std::promise<F>&p){
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout<<"生产者向承诺值传值"<<"\n";
    //2、std::current_exception()检索"抛出的异常"
    try{
        throw std::logic_error("就是一个异常");
    }catch(std::exception &e){
        p.set_exception(std::current_exception()); //std::current_exception()函数引用上文作用域抛出的异常
    }
}
template<typename T,typename...Args>
void Consumer(std::future<T>&f,Args&&...args){
    try{
        auto fun=f.get(); //阻塞提取,承诺值写入的异常将在期望值试图get()提取时在期望值所在的消费者线程中抛出
        auto fres=fun(std::forward<Args>(args)...);
        std::cout<<"消费者提取期望值,传递的函数运行结果:"<<fres<<"\n";
    }catch(std::logic_error &exp){
        std::cout<<"消费者线程捕获到期望值get()返回的异常:"<<exp.what()<<"\n";
    }
}
int main(int argc,char*argv[]){
    std::promise<F> pr1; //声明一个承诺值,将传入生产者线程
    std::future<F> fu1=pr1.get_future(); //声明一个期望值绑定到承诺值,将传入消费者线程
    int res(0);
    std::thread t1(Consumer<F,int,int,int&>,std::ref(fu1),1,2,std::ref(res));
    std::thread t2(Productor,std::ref(pr1));
    t1.join();
    t2.join();
}

macOS执行输出:

HaypinsMBP:MultiThread haypin$ clang++ -g std-promise.cpp -std=c++17 -o main
HaypinsMBP:MultiThread haypin$ ./main
生产者向承诺值传值
消费者线程捕获到期望值get()返回的异常:就是一个异常
HaypinsMBP:MultiThread haypin$ 

2、将函数打包进std::packaged_task<func_type,args_type>任务包后,打包函数如果抛出一个异常,这个异常将被返回给期望值(从而期望值状态被设置为"就绪"),在期望值调用get()时再次抛出,就像上面生产者线程中向承诺值写入异常,然后消费者线程中期望值调用get()会抛出异常一样。

3、函数作为std::async<func_type,args_type>的一部分时,当异步任务函数链抛出一个异常时,这个异常将返回到期望值,之后期望值的状态被设置为"就绪",然后期望值调用get()会抛出这个异常。

#include<iostream>
#include<thread>
#include<future>
#include<unistd.h>
#include<time.h>
double square(doublex){
    time_t nowt=time(nullptr);
    char* nowtc=new char[1<<10];
    nowtc=ctime(&nowt);
    std::cout<<nowtc<<"square thread echo\n";
    try{
    if(x<0){
        throw std::out_of_range("exception:square minus!");
    }
    }catch(std::exception &exp){
        std::cout<<"except in square thread:"<<&exp<<"\n";
        throw exp;
    }
    return sqrt(x);
    };
int main(int argc,char *argv[]){
    std::future<double>f=std::async(square,-1);
    sleep(1);
    std::cout<<"main thread echo\n";
    try{
        //double y(square(-1));
        std::cout<<f.get()<<"...\n";
        /*异步线程产生的异常将传递到主调线程中调用get()获取期望结果的执行中,从而实现在主调线程捕获异步子线程产生的异常*/
    }catch(std::exception &exp){
        std::cout<<"except in main thread:"<<&exp<<"\n";
        std::cout<<exp.what()<<"\n";
    }
}

macOS执行输出:

HaypinsMBP:MultiThreadhaypin$./main 
Thu Jan 28 21:35:39 2021 
square thread echo 
except in square thread:0x7fb88e6043b0 
main thread echo 
except in main thread:0x7fb88e604490 
std::exception 
HaypinsMBP:MultiThreadhaypin$

注意:标准并没有指定重新抛出的这std::exception异常对象是原始的异常对象还是一个拷贝;从上面macOS上执行结果看出,消费者线程中期望值get()到的异常是生产者async线程写入的异常的拷贝。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值