c++11 多线程支持 (std::shared_future)

  • A+
所属分类:C++11新特性
定义于头文件 <future>
template< class T > class shared_future;         (1) (C++11 起) 

template< class T > class shared_future<T&>;     (2) (C++11 起) 

template<>     class shared_future<void>;        (3) (C++11 起) 

类模板 std::shared_future 提供访问异步操作结果的机制,类似 std::future ,除了允许多个线程等候同一共享状态。不同于仅可移动的 std::future (故只有一个实例能指代任何特定的异步结果),std::shared_future 可复制而且多个 shared_future 对象能指代同一共享状态。

若每个线程通过其自身的 shared_future 对象副本访问,则从多个线程访问同一共享状态是安全的。

构造函数

shared_future() noexcept;                (1) (C++11 起) 

shared_future( const shared_future& other );  (2) (C++11 起) (C++17 前) 
shared_future( const shared_future& other ) noexcept;  (C++17 起) 

shared_future( std::future<T>&& other ) noexcept;     (3) (C++11 起) 

shared_future( shared_future&& other ) noexcept;      (4) (C++11 起) 

构造新的 shared_future

1) 默认构造函数。构造空的 shared_future ,它不指代共享状态,即 valid() == false 。

2) 构造与 other 指代同一共享状态的 shared_future ,若有共享状态。

3-4) 转移 other 所保有的共享状态给 *this 。构造后, other.valid() == false 且 this->valid() 返回与 other.valid() 在构造前会返回者相同的值。

参数

other - 用以初始化的另一 future 对象

 

析构函数

std::shared_future<T>::~shared_future
~shared_future();        (C++11 起) 

若 *this 是指代共享状态的最后一个对象,则销毁共享状态。否则不做任何事。

赋值内容

std::shared_future<T>::operator=
shared_future& operator=( const shared_future& other ); (C++11 起)(C++17 前) 

shared_future& operator=( const shared_future& other ) noexcept; (C++17 起) 

shared_future& operator=( shared_future&& other ) noexcept; (2) (C++11 起) 

shared_future& operator=( shared_future&& other ) noexcept;

(2) (C++11 起)

赋值另一 shared_future 的内容。

1) 释放任何共享状态并赋值 other 的内容给 *this 。赋值后, this->valid() == other.valid() 。

2) 释放任何共享状态并移动赋值 other 的内容给 *this 。赋值后, other.valid() == false 且 this->valid() 将产生与 other.valid() 在赋值前相同的值。

参数

other - 将转移状态给 *this 的 std::shared_future

返回值

*this

检查 future 是否拥有共享状态

std::shared_future<T>::valid
bool valid() const noexcept;    (C++11 起) 

检查期货是否指代共享状态。

这是非默认构造或被移动的期货的仅有情况。不同于 std::future ,调用 get() 时不非法化 std::shared_future 的共享状态。

若在不指代共享状态的 shared_future 上调用任何析构函数、复制赋值运算符、移动赋值运算符或 valid 以外的成员函数,则行为未定义(尽管鼓励实现在此情况下抛出指示 no_state 的 std::future_error )。从 valid()false 的 shared_future 对象移动或复制是合法的。

参数

(无)

返回值

若 *this 指代共享状态则为 true ,否则为 false 。

等待结果变得可用

std::shared_future<T>::wait
void wait() const;             (C++11 起) 

阻塞直至结果变得可用。调用后 valid() == true 。

若调用此函数前 valid()== false 则行为未定义。

参数

(无)

返回值

(无)

异常

(无)

注意

鼓励实现检测调用前 valid == false 的情况并抛出以 std::future_errc::no_state 为 error_condition 的 std::future_error 。

在同一 std::shared_future 上从多个线程调调用 wait 不安全;有意图的使用是令每个等待于同一共享状态上的线程拥有一个 std::shared_future 的副本。

调用示例

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

int fib(int n)
{
    if (n < 3)
    {
        return 1;
    }
    else
    {
        return fib(n - 1) + fib(n - 2);
    }
}

int main()
{
    std::shared_future<int> f1 = std::async(std::launch::async, []()
    {
        return fib(20);
    });
    std::shared_future<int> f2 = std::async(std::launch::async, []()
    {
        return fib(25);
    });

    std::cout << "waiting...\n";
    f1.wait();
    f2.wait();

    std::cout << "f1: " << f1.get() << '\n';
    std::cout << "f2: " << f2.get() << '\n';
}

输出

 

等待结果,如果在指定的超时间隔后仍然无法得到结果,则返回。

std::shared_future<T>::wait_for
template< class Rep, class Period >
std::future_status wait_for( 
const std::chrono::duration<Rep,Period>& timeout_duration ) const;(C++11 起) 

等待结果变得可用。阻塞直至经过指定的 timeout_duration ,或结果变为可用,两者的先到来者。返回值鉴别结果的状态。

此函数可能由于调度或资源争议延迟而阻塞长于 timeout_duration

推荐标准库用稳定时钟度量时长。若实现用系统时钟代替,则等待时间可能也对时钟调整敏感。

若调用此函数前 valid()== false 则行为未定义。

参数

timeout_duration - 要阻塞的最大时长

返回值

常量 解释
future_status::deferred 要计算结果的函数仍未启动
future_status::ready 结果就绪
future_status::timeout 已经过时限

异常

时钟、时间点或时长在执行中可能抛的任何异常(标准库提供的时钟、时间点和时长决不抛出)。

注意

鼓励实现在调用前检测 valid == false 的情况并抛出以 future_errc::no_state 为 error_condition 的 future_error 。

等待结果,如果在已经到达指定的时间点时仍然无法得到结果,则返回。

std::shared_future<T>::wait_until
template< class Clock, class Duration >
std::future_status wait_until( 
const std::chrono::time_point<Clock,Duration>& timeout_time ) const;  (C++11 起) 

wait_until 等待结果变为可用。它阻塞直至抵达指定的 timeout_time ,或结果变为可用,两者的先到来者。返回值指示 wait_until 为何返回。

若调用此函数前 valid()== false 则行为未定义。

参数

timeout_time - 要阻塞到的最大时间点

返回值

常量 解释
future_status::deferred 要计算结果的函数仍未启动
future_status::ready 结果就绪
future_status::timeout 已经过时限

异常

时钟、时间点或时长在执行中可能抛的任何异常(标准库提供的时钟、时间点和时长决不抛出)。

注意

鼓励实现在调用前检测 valid == false 的情况并抛出以 future_errc::no_state 为 error_condition 的 future_error 。

使用倾向 timeout_time 的时钟,不要求是单调时钟。若不连续地调节时钟,则不对此函数的行为保证,但既存实现将 timeout_timeClock 转换到 std::chrono::system_clock ,并委托 POSIX pthread_cond_timedwait 以令等待忠实于系统时钟,但非用户提供 Clock 的调节。任何情况下,由于调度或资源争议延迟,函数可能等待长于抵达 timeout_time

返回结果

std::shared_future<T>::get
const T& get() const; (1) (仅为泛型 shared_future 模板的成员) (C++11 起) 

T& get() const; (2) (仅为 shared_future<T&> 模板特化的成员)(C++11 起) 

void get() const; (3) (仅为 shared_future<void> 模板特化的成员)(C++11 起) 

get 方法等待直至 shared_future 拥有合法结果并(依赖于使用哪个模板)获取它。它等效地调用 wait() 等待结果。

泛型模板和二个模板特化各含单个 get 版本。 get 的三个版本仅在返回类型有别。

若调用此函数前 valid() 为 false 则行为未定义。

参数

(无)

返回值

1) 到存储于共享状态的值的 const 引用。销毁共享状态后,通过此引用访问值是未定义行为。

2) 存储于共享状态的值的引用。

3) 无。

异常

若 future 所引用的共享状态中存储异常(例如,通过调用 std::promise::set_exception() ),则抛出该异常。

注意

鼓励实现在调用前检测 valid() 为 false 的情况,并抛出以 std::future_errc::no_state 为 error_condition 的 std::future_error 。

调用示例

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

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(); // 等待来自 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(); // 等待来自 main() 的信号
        return std::chrono::high_resolution_clock::now() - start;
    };

    auto result1 = std::async(std::launch::async, fun1);
    auto result2 = std::async(std::launch::async, fun2);

    // 等待线程变为就绪
    t1_ready_promise.get_future().wait();
    t2_ready_promise.get_future().wait();

    // 线程已就绪,开始时钟
    start = std::chrono::high_resolution_clock::now();

    // 向线程发信使之运行
    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";
}

输出

 

w3cjava

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: