C++11中的std::shared_future是个模板类。std::future类似,std::shared_future提供了一种访问异步操作结果的机制;不同于std::future,std::shared_future允许多个线程等待同一个共享状态;不同于std::future仅支持移动操作,std::shared_future既支持移动操作也支持拷贝操作,而且多个shared_future对象可以引用相同的共享状态。std::shared_future还允许一旦共享状态就绪就可以多次检索共享状态下的值(A shared_future object behaves like a future object, except that it can be copied, and that more than one shared_future can share ownership over their end of a shared state. They also allow the value in the shared state to be retrieved multiple times once ready)。

std::shared_future对象可以通过std::future对象隐式转换,也可以通过显示调用std::future::share显示转换,在这两种情况下,原std::future对象都将变得无效。

共享状态(shared state)的生存期至少要持续到与之关联的最后一个对象被销毁为止。与std::future不同,通过shared_future::get检索的值不会释放共享对象的所有权。

std::future介绍参考:https://blog.csdn.net/fengbingchun/article/details/104115489

当你需要具有std::future的多个有效拷贝时会用到std::shared_future;或者多个使用者使用std::future时也会用到std::shared_future。

Consider std::future, std::shared_future to be like std::unique_ptr, std::shared_ptr.

模板类std::shared_future成员函数包括:

1. 构造函数:(1).不带参数的默认构造函数,此对象没有共享状态,因此它是无效的,但是它可以被赋予一个有效值;(2).拷贝构造:与const shared_future& x具有相同的共享状态,并与之共享所有权;(3).支持移动构造。

2. 析构函数:销毁shared_future对象,它是异常安全的。如果对象有效(即它可以访问共享状态),则将其与对象接触关联;如果它是与共享状态关联的唯一对象,则共享对象本身也将被销毁。

3. get函数:(1).当共享状态就绪时,返回存储在共享状态中的值的引用(或抛出异常)。(2).如果共享状态尚未就绪(即provider提供者尚未设置其值或异常),则该函数将阻塞调用的线程直到就绪。(3).当共享状态就绪后,则该函数将解除阻塞并返回(或抛出),但与future::get不同,不会释放其共享状态,允许其它shared_future对象也访问存储的值。(4).std::shared_future<void>::get()不返回任何值,但仍等待共享状态就绪才返回或抛出。

4. operator=:(1).拷贝赋值:该对象与const shared_future& rhs关联到相同的共享状态,并与之共享所有权;(2).移动赋值:该对象获取shared_future&& rhs的共享状态,rhs不再有效。

5. valid函数:检查共享状态的有效性,返回当前的shared_future对象是否与共享状态关联。

6. wait函数:(1).等待共享状态就绪。(2).如果共享状态尚未就绪(即提供者尚未设置其值或异常),则该函数将阻塞调用的线程直到就绪。(3).当共享状态就绪后,则该函数将解除阻塞并void返回。

7. wait_for函数:(1).等待共享状态在指定的时间内(time span)准备就绪。(2). 如果共享状态尚未就绪(即提供者尚未设置其值或异常),则该函数将阻塞调用的线程直到就绪或已达到设置的时间。(3).此函数的返回值类型为枚举类future_status。此枚举类有三种label:ready:共享状态已就绪;timeout:在指定的时间内未就绪;deferred:共享状态包含了一个延迟函数(deferred function)。(4).如果共享状态包含了一个延迟函数,则该函数不会阻塞,立即返回一个future_status::deferred值。

8. wait_until函数:(1). 等待共享状态在指定的时间点(time point)准备就绪。(2). 如果共享状态尚未就绪(即提供者尚未设置其值或异常),则该函数将阻塞调用的线程直到就绪或已达到指定的时间点。(3).此函数的返回值类型为枚举类future_status。(4).如果共享状态包含了一个延迟函数,则该函数不会阻塞,立即返回一个future_status::deferred值。

详细用法见下面的测试代码,下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "future.hpp"
#include <iostream>
#include <future>
#include <chrono>
#include <utility>
#include <thread>

namespace future_ {

///
// reference: https://en.cppreference.com/w/cpp/thread/shared_future
int test_shared_future_1()
{
	std::promise<void> ready_promise, t1_ready_promise, t2_ready_promise;
	// 通过std::future移动构造std::shared_future对象,t1_ready_promise和t2_ready_promise均会用到ready_future
	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";

	return 0;
}

///
// reference: https://en.cppreference.com/w/cpp/thread/shared_future/wait
int fib(int n)
{
	if (n < 3) return 1;
	else return fib(n - 1) + fib(n - 2);
}

int test_shared_future_2()
{
	// 将std::shared_future<int>调整为std::future<int>也是正确的
	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';

	return 0;
}

///
// reference: https://en.cppreference.com/w/cpp/thread/shared_future/wait_for
int test_shared_future_3()
{
	// 将std::shared_future<int>调整为std::future<int>也是正确的
	std::shared_future<int> future = std::async(std::launch::async, [](){ 
        std::this_thread::sleep_for(std::chrono::seconds(3));
        return 8;  
    }); 
 
    std::cout << "waiting...\n";
    std::future_status status;
    do {
        status = future.wait_for(std::chrono::seconds(1));
        if (status == std::future_status::deferred) {
            std::cout << "deferred\n";
        } else if (status == std::future_status::timeout) {
            std::cout << "timeout\n";
        } else if (status == std::future_status::ready) {
            std::cout << "ready!\n";
        }
    } while (status != std::future_status::ready); 
 
    std::cout << "result is " << future.get() << '\n';

	return 0;
}

} // namespace future_

GitHubhttps://github.com/fengbingchun/Messy_Test

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐