C++异步--future&promise&packed_task&async

C++异步的使用场景:一个线程需要获取其他线程中的值。
麻烦但直接做法,定义一个全局变量,然后用条件变量进行同步。
C++11提供了更简洁的方法实现。

std::future

作用

future的作用是阻塞调用线程,直到工作线程获得所需要的值或异常

特性

  1. 不能拷贝,只能移动
  2. 所存储的可能是异常
  3. API
  • get()阻塞该函数直到获得相应的值
  • wait()阻塞直到结果就绪
  • wait_for()等待一段时间,返回future_status(见下)
  • wait_until()等待到一个时间点,返回future_status
  • valid()检查未来提是否拥有共享状态
  1. future_status

future_status(枚举值)为wait_for()或者wait_until()的返回值,有三种状态

enum class future_status {
  ready,//状态就绪
  timeout,//时间耗尽也为就绪
  deferrd//函数被推迟执行
};

promise

用法

从调用get_future()方法获取future对象,再将promise通过引用、指针或右值引用等方法将promise传递到另一个线程,在对promise对象调用set_value()等方法传回主线程所期待的值。promise只能使用一次

API

  1. get_future() 返回与promise关联的future
  2. set_value() 设置结果为指定值
  3. set_value_at_thread_exit() 设置结果为指定值,子线程资源被销毁后数据才就绪
  4. set_exception()设置结果为指示异常
  5. set_exception_at_thread_exit()

示例

代码来源

#include <chrono>
#include <future>
#include <iostream>
#include <numeric>
#include <thread>
#include <vector>
 
void accumulate(std::vector<int>::iterator first,
                std::vector<int>::iterator last,
                std::promise<int> accumulate_promise)
{
    int sum = std::accumulate(first, last, 0);
    accumulate_promise.set_value(sum); // 提醒 future
}
 
void do_work(std::promise<void> barrier)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    barrier.set_value();
}
 
int main()
{
    // 演示用 promise<int> 在线程间传递结果。
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6};
    std::promise<int> accumulate_promise;
    //获得与promise关联的future
    std::future<int> accumulate_future = accumulate_promise.get_future();
    //右值引用的方式将std::promise对象传递到子线程中区
    std::thread work_thread(accumulate, numbers.begin(), numbers.end(),
                            std::move(accumulate_promise));
 
    // future::get() 将等待直至该 future 拥有合法结果并取得它
    // 无需在 get() 前调用 wait()
    // accumulate_future.wait(); // 等待结果
    std::cout << "result=" << accumulate_future.get() << '\n';
    work_thread.join(); // wait for thread completion
 
    // 演示用 promise<void> 在线程间对状态发信号
    std::promise<void> barrier;
    std::future<void> barrier_future = barrier.get_future();
    std::thread new_work_thread(do_work, std::move(barrier));
    barrier_future.wait();
    new_work_thread.join();
}

packaged_task

用法:

包装一个可调用对象,将其返回值或异常储存在与其相关联的future中

API:

  1. get_future()返回关联的future对象
  2. operator()调用包装的可执行对象
  3. make_ready_at_thread_exit()线程退出后使future就绪
  4. reset()重置状态

代码来源

#include <cmath>
#include <functional>
#include <future>
#include <iostream>
#include <thread>
 
// 避免对 std::pow 重载集消歧义的独有函数
int f(int x, int y) { return std::pow(x,y); }
 
void task_lambda()
{
    std::packaged_task<int(int, int)> task([](int a, int b)
    {
        return std::pow(a, b); 
    });
    std::future<int> result = task.get_future();
 
    task(2, 9);
 
    std::cout << "task_lambda:\t" << result.get() << '\n';
}
 
void task_bind()
{
    std::packaged_task<int()> task(std::bind(f, 2, 11));
    std::future<int> result = task.get_future();
 
    task();
 
    std::cout << "task_bind:\t" << result.get() << '\n';
}
 
void task_thread()
{
    std::packaged_task<int(int, int)> task(f);
    std::future<int> result = task.get_future();
 
    std::thread task_td(std::move(task), 2, 10);
    task_td.join();
 
    std::cout << "task_thread:\t" << result.get() << '\n';
}
 
int main()
{
    task_lambda();
    task_bind();
    task_thread();
}

async

用法

异步运行一个函数,将返回值储存在与之关联的future中。函数可能在一个新线程中执行,也可能在原线程中执行

template< class F, class... Args >
  async( F&& f, Args&&... args );
template< class F, class... Args >
  async( std::launch policy, F&& f, Args&&... args );

返回一个与之关联的future对象

启动策略—launch

async函数第一个参数可为launch
launch是

enum class launch : {
  async,
  deferred,
};

launch::async表示为创建一个新的线程异步执行任务
launch::deferred表示直到相关联的future调用get()或wait()等函数才执行,不创建新线程
如果不指定调度策略,则由标准库的调度器决定由哪种方式执行,
相当于std::launch::async | std::launch::deferred
代码来源

#include <algorithm>
#include <future>
#include <iostream>
#include <mutex>
#include <numeric>
#include <string>
#include <vector>
 
std::mutex m;
 
struct X
{
    void foo(int i, const std::string& str)
    {
        std::lock_guard<std::mutex> lk(m);
        std::cout << str << ' ' << i << '\n';
    }
 
    void bar(const std::string& str)
    {
        std::lock_guard<std::mutex> lk(m);
        std::cout << str << '\n';
    }
 
    int operator()(int i)
    {
        std::lock_guard<std::mutex> lk(m);
        std::cout << i << '\n';
        return i + 10;
    }
};
 
template<typename RandomIt>
int parallel_sum(RandomIt beg, RandomIt end)
{
    auto len = end - beg;
    if (len < 1000)
        return std::accumulate(beg, end, 0);
 
    RandomIt mid = beg + len / 2;
    auto handle = std::async(std::launch::async,
                             parallel_sum<RandomIt>, mid, end);
    int sum = parallel_sum(beg, mid);
    return sum + handle.get();
}
 
int main()
{
    std::vector<int> v(10000, 1);
    std::cout << "和为 " << parallel_sum(v.begin(), v.end()) << '\n';
 
    X x;
    // 以默认策略调用 x.foo(42, "Hello") :
    // 可能同时打印 "Hello 42" 或延迟执行
    auto a1 = std::async(&X::foo, &x, 42, "Hello");
    // 以 deferred 策略调用 x.bar("world!")
    // 调用 a2.get() 或 a2.wait() 时打印 "world!"
    auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
    // 以 async 策略调用 X()(43) :
    // 同时打印 "43"
    auto a3 = std::async(std::launch::async, X(), 43);
    a2.wait();                     // 打印 "world!"
    std::cout << a3.get() << '\n'; // 打印 "53"
} // 若 a1 在此点未完成,则 a1 的析构函数在此打印 "Hello 42"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值