C++笔记--future
Posted ljt2724960661
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++笔记--future相关的知识,希望对你有一定的参考价值。
这一节学习C++里面的future,在多线程里面, 如果等待线程只打算等待一次,那么当条件为 true 时它就不会再等待这个条件变量了,条件变量未必是同步机制的最佳选择。如果所等待的条件是一个特定数据块的可用性时,这尤其正确。在这个场景中,使用期值(future)可能会更合适。<future> 头文件中包含了以下几个类和函数:
Providers 类:std::promise, std::package_task
Futures 类:std::future, std::shared_future.
Providers 函数:std::async()
其他类型:std::future_error, std::future_errc, std::future_status, std::launch.
使用 Future 等待一次性事件
标准库模型将这种一次性事件称为期望(future)。当一个线程需要等待一个特定的一次性事件时,在某种程度上来说它就需要知道这个事件在未来的表现形式。之后,这个线程会周期性(较短的周期)的等待或检查,事件是否触发(检查信息板);在检查期间也会执行其他任务(品尝昂贵的咖啡)。另外,在等待任务期间它可以先执行另外一些任务,直到对应的任务触发,而后等待期望的状态会变为就绪(ready)。一个“期望”可能是数据相关的(比如,你的登机口编号),也可能不是。当事件发生时(并且期望状态为就绪),这个“期望”就不能被重置。
在C++标准库中,有两种“期望”,使用两种类型模板实现,声明在头文件中: 唯一期望(unique futures)(std::future<>
)和共享期望(shared futures)(std::shared_future<>
)。这是仿照std::unique_ptr
和std::shared_ptr
。std::future
的实例只能与一个指定事件相关联,而std::shared_future
的实例就能关联多个事件。后者的实现中,所有实例会在同时变为就绪状态,并且他们可以访问与事件相关的任何数据。这种数据关联与模板有关,比如std::unique_ptr
和std::shared_ptr
的模板参数就是相关联的数据类型。在与数据无关的地方,可以使用std::future<void>
与std::shared_future<void>
的特化模板。虽然,希望用于线程间的通讯,但是“期望”对象本身并不提供同步访问。当多个线程需要访问一个独立“期望”对象时,他们必须使用互斥量或类似同步机制对访问进行保护,多个线程会对一个std::shared_future<>
实例的副本进行访问,而不需要期望同步,即使他们是同一个异步结果。最基本的一次性事件,就是一个后台运行出的计算结果。
从后台任务中返回值
假设你有一个长期运行的计算,预期最终将得到一个有用的结果,但是现在,你还不需要这个值。你可以启动一个新的线程来执行该计算,但这也意味着你必须注意将结果传回来,因为 std:: thread 并没有提供直接的机制来这样做。这就是 std:: async 函数模板(同样声明于< future>头文件中)的由来。
在不需要立刻得到结果的时候,你可以使用 std::async 来启动一个异步任务( asynchronous task )。 std::async 返回一个 std:: future 对象,而不是给你一个std: : thread 对象让你在上面等待, std:: future 对象最终将持有函数的返回值。当你需要这个值时,只要在 future 上调用 get (),线程就会阻塞直到“ture 就绪,然后返回该值。如下:
#include <future>
#include <iostream>
int find_the_answer_to_ltuae();
void do_other_stuff();
int main()
std::future<int> the_answer=std::async(find_the_answer_to_ltuae);
do_other_stuff();
std::cout<<"The answer is "<<the_answer.get()<<std::endl;
分析: 与std::thread 做的方式一样,std::async允许你通过添加额外的调用参数,向函数传递额外的参数。当第一个参数是一个指向成员函数的指针,第二个参数提供有这个函数成员类的具体对象(不是直接的,就是通过指针,还可以包装在std::ref中),剩余的参数可作为成员函数的参数传入。否则,第二个和随后的参数将作为函数的参数,或作为指定可调用对象的第一个参数。就如std::thread,当参数为右值(rvalues)时,拷贝操作将使用移动的方式转移原始数据。这就允许使用“只移动”类型作为函数对象和参数。
异步任务提供者(Provider)
这里主要说Promise,Promise 对象可以保存某一类型 T 的值,该值可被 future 对象读取(可能在另外一个线程中),因此 promise 也提供了一种线程同步的手段。在 promise 对象构造时可以和一个共享状态(通常是std::future)相关联,并可以在相关联的共享状态(std::future)上保存一个类型为 T 的值。
std::promise 构造函数
1 default promise();
2 with allocator template <class Alloc> promise (allocator_arg_t aa, const Alloc& alloc);
3 copy [deleted] promise (const promise&) = delete;
4 move promise (promise&& x) noexcept;
1 默认构造函数,初始化一个空的共享状态。2 带自定义内存分配器的构造函数,与默认构造函数类似,但是使用自定义分配器来分配共享状态。3 拷贝构造函数,被禁用。4 移动构造函数。
栗子:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <future> // std::promise, std::future
std::promise<int> prom;
void print_global_promise ()
std::future<int> fut = prom.get_future();
int x = fut.get();
std::cout << "value: " << x << '\\n';
int main ()
std::thread th1(print_global_promise);
prom.set_value(10);
th1.join();
prom = std::promise<int>(); // prom 被move赋值为一个新的 promise 对象.
std::thread th2 (print_global_promise);
prom.set_value (20);
th2.join();
return 0;
分析: 可以通过 get_future 来获取与该 promise 对象相关联的 future 对象,调用该函数之后,两个对象共享相同的共享状态(shared state)
promise 对象是异步 Provider,它可以在某一时刻设置共享状态的值。future 对象可以异步返回共享状态的值,或者在必要的情况下阻塞调用者并等待共享状态标志变为 ready,然后才能获取共享状态的值。
#include <iostream> // std::cout
#include <functional> // std::ref
#include <thread> // std::thread
#include <future> // std::promise, std::future
void print_int(std::future<int>& fut)
int x = fut.get(); // 获取共享状态的值.
std::cout << "value: " << x << '\\n'; // 打印 value: 10.
int main ()
std::promise<int> prom; // 生成一个 std::promise<int> 对象.
std::future<int> fut = prom.get_future(); // 和 future 关联.
std::thread t(print_int, std::ref(fut)); // 将 future 交给另外一个线程t.
prom.set_value(10); // 设置共享状态的值, 此处和线程t保持同步.
t.join();
return 0;
std::promise::set_exception
为 promise 对象设置异常,此后 promise 的共享状态变标志变为 ready,例子如下,线程1从终端接收一个整数, 线程 2 将该整数打印出来,如果线程 1 接收一个非整数,则为 promise 设置一个异常(failbit) ,线程 2 在 std::future::get 是抛出该异常。
#include <iostream> // std::cin, std::cout, std::ios
#include <functional> // std::ref
#include <thread> // std::thread
#include <future> // std::promise, std::future
#include <exception> // std::exception, std::current_exception
void get_int(std::promise<int>& prom)
int x;
std::cout << "Please, enter an integer value: ";
std::cin.exceptions (std::ios::failbit); // throw on failbit
try
std::cin >> x; // sets failbit if input is not int
prom.set_value(x);
catch (std::exception&)
prom.set_exception(std::current_exception());
void print_int(std::future<int>& fut)
try
int x = fut.get();
std::cout << "value: " << x << '\\n';
catch (std::exception& e)
std::cout << "[exception caught: " << e.what() << "]\\n";
int main ()
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread th1(get_int, std::ref(prom));
std::thread th2(print_int, std::ref(fut));
th1.join();
th2.join();
return 0;
以上是关于C++笔记--future的主要内容,如果未能解决你的问题,请参考以下文章