# c++中的std::future与std::shared_future

# std::future

在C++中,std::future 是一个类模板,用于接收尚未计算的异步执行任务的结果,也就是未来值,用来获取异步操作的未来值

获取std::future 对象的三种方式:

  • std::async
  • std::packaged_taskget_future函数
  • std::promiseget_future函数

异步操作准备将一个修改发布给future对象时,可以通过修改和future对象关联的共享状态来实现,如std::promise::set_value方法。

std::future模板类支持的成员函数有:

  • future& operator=( future&& other ) noexcept;将一个future对象移动给当前变量
  • std::shared_future<T> share() noexcept;传输*this的共享状态,多个std::shared_future对象可以在多个线程共享同个共享状态。
  • T get()获取future对象的关联结果
  • wait等待直到结果获取到值
  • wait_for/wait_until等待,并设置超时

# std::shared_future

功能总体和std::future相同,都是为了从异步操作中获取函数执行的结果。

不过,使用std::shared_future可以使得多个线程支持共同等待同一共享变量的值。

std::future相比,std::shared_future类的对象支持复制,支持多个std::shared_future对象关联同个共享状态值。

如果每个线程复制获取了std::shared_future对象,那么同时在多个线程中获取同个共享状态也是线程安全的。

std::shared_future的机制有些类似条件变量,同时给所有等待的线程发信号。

# 实例

  • std::future
#include <future>
#include <thread>
#include <iostream>

void setPromiseValue1(std::future<int> &fut)
{
    std::cout << "waitting1 to get value" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    int value = fut.get();
    std::cout << "promise1 value: " << value << std::endl;
}

int main(int argc, char* argv[])
{
    std::promise<int> prom;
    std::future<int> fut = prom.get_future();
    std::thread t1(setPromiseValue1, std::ref(fut));
    std::cout << "before set value...\n";
    prom.set_value(100);
    t1.join();
}
// before set value...
// waitting1 to get value
// promise1 value: 100

上面的例子,如果再创建一个线程,依然使用fut对象,并在线程任务中调用fut.get,那么程序将报错,因为std::future对象不支持多个线程共享,get也仅支持调用一次。

  • std::shared_future
#include <chrono>
#include <future>
#include <iostream>
 
int main()
{   
    std::promise<void> ready_promise, t1_ready_promise, t2_ready_promise;
    std::shared_future<void> ready_future(ready_promise.get_future());
 
    std::chrono::time_point<std::chrono::high_resolution_clock> start;
 
    auto fun1 = [&, ready_future]() -> std::chrono::duration<double, std::milli> 
    {
        t1_ready_promise.set_value();
        ready_future.wait(); // waits for the signal from main()
        return std::chrono::high_resolution_clock::now() - start;
    };
 
    auto fun2 = [&, ready_future]() -> std::chrono::duration<double, std::milli> 
    {
        t2_ready_promise.set_value();
        ready_future.wait(); // waits for the signal from main()
        return std::chrono::high_resolution_clock::now() - start;
    };
 
    auto fut1 = t1_ready_promise.get_future();
    auto fut2 = t2_ready_promise.get_future();
 
    auto result1 = std::async(std::launch::async, fun1);
    auto result2 = std::async(std::launch::async, fun2);
 
    // wait for the threads to become ready
    fut1.wait();
    fut2.wait();
 
    // the threads are ready, start the clock
    start = std::chrono::high_resolution_clock::now();
 
    // signal the threads to go
    ready_promise.set_value();
 
    std::cout << "Thread 1 received the signal "
              << result1.get().count() << " ms after start\n"
              << "Thread 2 received the signal "
              << result2.get().count() << " ms after start\n";
}

上面的代码中ready_promise返回的是ready_future,两个线程中都有调用其wait阻塞,直到与之关联的ready_promise设置值后才会继续运行。

# reference

1.https://en.cppreference.com/w/cpp/thread/future (opens new window)
2.https://en.cppreference.com/w/cpp/thread/shared_future (opens new window)