《深入应用C++11》笔记-异步线程操作std::async、std::future、std::promise、std::packaged_task

本文介绍了C++11中异步编程的相关内容,包括std::async和std::future,前者可异步执行回调函数并返回后者,后者存储线程函数结果;还介绍了std::promise、std::packaged_task,分别可保存值和包装可调用对象,允许异步获取结果。

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

上一篇:《深入应用C++11》笔记-互斥量std::mutex、锁std::lock_guard

 

std::async和std::future

 

std::async()是一个接受回调函数或函数对象作为参数的函数模板,并可以异步执行它们。通过这个异步接口可以很方便的获取线程函数的执行结果,std::async会自动创建一个线程去调用线程函数,它返回一个std::future。

 

std::future中存储了线程函数返回的结果,当我们需要线程函数的结果时,直接从future中获取。std::async首先解耦了线程的创建和执行,使得我们可以在需要的时候获取异步操作的结果;其次它还提供了线程的创建策略(比如可以通过延迟加载的方式去创建线程),可以以多种方式去创建线程。

 

 

 

template<class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type> async(launch policy, Fn&& fn, Args&&...args);12

 

std::async中的第一个参数是启动策略,它控制std::async的异步行为,共有三类:

 


std::launch::async:立即开始执行线程
std::launch::deferred:调用get()函数时才开始执行线程
std::launch::async | std::launch::deferred:默认行为。有了这个启动策略,它可以异步运行或不运行,这取决于系统的负载,但我们无法控制它。

 

 

 


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

 

int func()
{
    std::cout << "run async" << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    return 1;
}

 

int main()
{
    auto handle = std::async(std::launch::async, func);
    // 用deferred输出结果顺序将会不同
    //auto handle = std::async(std::launch::deferred, func);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "do something" << std::endl;
    std::cout << handle.get() << std::endl;

 

    return 0;
}

 

输出结果:
run async
do something
1123456789101112131415161718192021222324252627

 

可以看到,std::async异步执行了func函数,并且能够通过handle获取到func函数的返回值。

 

返回值handle实际上是std::future模板类对象,可使用std::future::get获取结果,如果调用过程中,任务尚未完成,则主线程阻塞至任务完成。也可使用std::future::wait_for等待结果返回,wait_for可设置超时时间,如果在超时时间之内任务完成,则返回std::future_status::ready状态;如果在超时时间之内任务尚未完成,则返回std::future_status::timeout状态。更加详细的用法参考:https://blog.youkuaiyun.com/watson2016/article/details/52860797

 

std::promise

 

promise 对象可以保存某一类型 T 的值,该值可被 future 对象读取。可以通过 get_future 来获取与该 promise 对象相关联的 future 对象,调用该函数之后,两个对象共享相同的共享状态(shared state)。

 

 

 

#include <iostream>
#include <functional>
#include <thread>
#include <future>

 

void func(std::promise<int>& pro){
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
    pro.set_value(10);                         // 设置值
}

 

int main()
{
    std::promise<int> pro;
    std::thread t(func, std::ref(pro));

 

    std::future<int> fut = pro.get_future();
    std::cout << fut.get() << std::endl;      // 10,调用get函数等待pro设置值
    t.join();

 

    return 0;
}123456789101112131415161718192021

 

另外std::promise还提供了set_exception函数,让future对象的get函数抛出异常;提供set_value_at_thread_exit用于在线程退出时设置值,也就是说直到线程退出get阻塞才会结束,并且std::promise对象不能在线程结束前被释放。

 

std::packaged_task

 

std::packaged_task 和 std::promise很类似,不过他包装一个可调用的对象而不是类型对象,并且允许异步获取该可调用对象产生的结果。

 

 

 

int func(int from, int to) {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return from - to;
}

 

int main()
{
    std::packaged_task<int(int, int)> task(func);
    std::future<int> ret = task.get_future();

 

    std::thread th(std::move(task), 10, 5);
    std::cout << ret.get() << std::endl;          // 5,调用get函数等待func的返回值

 

    th.join();

 

    return 0;
}1234567891011121314151617

 

valid函数,判断是否有效,对于由默认构造函数生成的 packaged_task 对象,该函数返回 false:

 

 

 

std::future<int> launcher(std::packaged_task<int(int)>& tsk, int arg)
{
    if (tsk.valid()) {                         // 无效返回false
        std::future<int> ret = tsk.get_future();
        std::thread(std::move(tsk), arg).detach();
        return ret;
    }
    else return std::future<int>();
}

 

int main()
{
    std::packaged_task<int(int)> tsk;         // 没有给packaged_task初始化

 

    std::future<int> fut = launcher(tsk, 25);

 

    if (fut.valid())                          // 无效返回false
    {
        std::cout << << fut.get() << std::endl;
    }

 

    return 0;
}1234567891011121314151617181920212223

std::packaged_task还提供了reset函数,用于重置std::packaged_task状态,让他能够再次调用;提供make_ready_at_thread_exit函数,直到线程退出get阻塞才会结束,而不是可调用对象结束时。
---------------------
作者:WizardtoH
原文:https://blog.youkuaiyun.com/WizardtoH/article/details/81635669
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值