- providers future 和 智能指针有点类似
future对应智能指针;
providers对应智能指针指向的存储区域;
当所有与shared state关联的future对象都销毁时,shared state也会销毁。
1.Providers
1.1 promise
template <class T> promise;
template <class R&> promise<R&>; // specialization : T is a reference type (R&)
template <> promise<void>; // specialization : T is void
- promise存储的T类型的值,可以被future对象获取。promise提供了一个同步点。
- 只有当所有的连接到promise的future对象都销毁时,promise对象才会被析构
- 构造函数如下
//default (1)
promise();
//with allocator (2)
template <class Alloc> promise (allocator_arg_t aa, const Alloc& alloc);
//copy [deleted] (3)
promise (const promise&) = delete;
//move (4)
promise (promise&& x) noexcept;
// promise constructors
#include <iostream> // std::cout
#include <functional> // std::ref
#include <memory> // std::allocator, std::allocator_arg
#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';
}
int main ()
{
std::promise<int> foo;
std::promise<int> bar = std::promise<int>(std::allocator_arg,std::allocator<int>());
std::future<int> fut = bar.get_future();
std::thread th (print_int, std::ref(fut));
bar.set_value (20); // fulfill promise
// (synchronizes with getting the future)
th.join();
return 0;
}
- get_future
返回连接到promise对象共享状态的future 对象。
当该函数调用时,promise承诺在未来某个时间点(通过设置值或者异常)使它的共享状态可用。
当设置好值或异常时,future对象就可以获取该共享状态的值。
future<T> get_future();
- set_value
在共享状态里存储值,此时shared state变为可用。
如果此时有一个future对象正在等待此状态可用(调用future::get),它会解锁并返回该值。
// generic template (1)
void set_value (const T& val);
void set_value (T&& val);
//specializations (2)
void promise<R&>::set_value (R& val); // when T is a reference type (R&)
void promise<void>::set_value (void); // when T is void
- set_exception
只不过将值变为了exception。其他过程跟set_value一致。get()获得该异常时,会将异常抛出。
void set_exception (exception_ptr p);
// promise::set_exception
#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 (print_int, std::ref(fut));
std::thread th2 (get_int, std::ref(prom));
th1.join();
th2.join();
return 0;
}
- set_value_at_thread_exit
设置值后不会立马将shared state变为可用,要直到线程退出时才可用。
在设置值到线程退出期间,任何修改此shared state值的操作都会抛出错误promise_already_satisfied。 - set_exception_at_thread_exit
类似
1.2 packaged_task——同步机制和promise一致
- packaged_task封装一个可调用的对象,其返回值可以被获取。
- 包含两个元素
1)一个任务。是一个可调用对象(函数指针、函数对象指针),调用签名(call signature):参数类型是Args,返回Ret类型。
2)一个共享状态shared state。存储调用任务的结果,可以被future获取。
template <class T> packaged_task; // undefined
template <class Ret, class... Args> class packaged_task<Ret(Args...)>;
- 构造函数
//default (1)
packaged_task() noexcept;
//initialization (2)
template <class Fn>
explicit packaged_task (Fn&& fn);
//with allocator (3)
template <class Fn, class Alloc>
explicit packaged_task (allocator_arg_t aa, const Alloc& alloc, Fn&& fn);
//copy [deleted] (4)
packaged_task (packaged_task&) = delete;
//move (5)
packaged_task (packaged_task&& x) noexcept;
// packaged_task construction / assignment
#include <iostream> // std::cout
#include <utility> // std::move
#include <future> // std::packaged_task, std::future
#include <thread> // std::thread
int main ()
{
std::packaged_task<int(int)> foo; // default-constructed
std::packaged_task<int(int)> bar ([](int x){return x*2;}); // initialized
foo = std::move(bar); // move-assignment
std::future<int> ret = foo.get_future(); // get future
std::thread(std::move(foo),10).detach(); // spawn thread and call task
// ...
int value = ret.get(); // wait for the task to finish and get result
std::cout << "The double of 10 is " << value << ".\n";
return 0;
}
- valid
默认初始化的对象返回false。
bool valid() const noexcept;
- get_future
当packaged_task对象的任务被调用时,shared state会被设置值或异常,此时future就可以获取该值。 - make_ready_at_thread_exit——也是调用运算符
类似于operator(),在线程退出设置shared state可用。跟promise相应的成员函数类似
void make_ready_at_thread_exit (args... args);
- reset
// packaged_task::get_future
#include <iostream> // std::cout
#include <utility> // std::move
#include <future> // std::packaged_task, std::future
#include <thread> // std::thread
// a simple task:
int triple (int x) { return x*3; }
int main ()
{
std::packaged_task<int(int)> tsk (triple); // package task
std::future<int> fut = tsk.get_future();
tsk(33);
std::cout << "The triple of 33 is " << fut.get() << ".\n";
// re-use same task object:
tsk.reset();
fut = tsk.get_future();
std::thread(std::move(tsk),99).detach();
std::cout << "Thre triple of 99 is " << fut.get() << ".\n";
return 0;
}
2.Futures
2.1 future
- future对象关联到shared state,在调用如下函数时被构造:
1)async
2)promise::get_future
3)packaged_task::get_future - 在一个有效的future对象上调用futuer::get会阻塞其线程,直到provider让shared state变得可用(设置值或者异常)。
- 移动赋值
//move (1)
future& operator= (future&& rhs) noexcept;
//copy [deleted] (2)
future& operator= (const future&) = delete;
// future::operator=
#include <iostream> // std::cout
#include <future> // std::async, std::future
int get_value() { return 10; }
int main ()
{
std::future<int> fut; // default-constructed
fut = std::async (get_value); // move-assigned
std::cout << "value: " << fut.get() << '\n';
return 0;
}
- share
当前的future对象的shared state不再有效。
shared_future<T> share();
// 类似于采用移动构造函数
shared_future<T>(std::move(*this)
get
如果shared state不可用时,阻塞等待。
可用时,线程解除阻塞,返回并释放shared state。使得future对象变为无效。
该函数对每个future shared state只能调用一次。valid
检查future对象是否和shared state关联wait
阻塞的效果和get一样,只不过解除阻塞后不会读取shared state的值。
// future::wait
#include <iostream> // std::cout
#include <future> // std::async, std::future
#include <chrono> // std::chrono::milliseconds
// a non-optimized way of checking for prime numbers:
bool is_prime (int x) {
for (int i=2; i<x; ++i) if (x%i==0) return false;
return true;
}
int main ()
{
// call function asynchronously:
std::future<bool> fut = std::async (is_prime,194232491);
std::cout << "checking...\n";
fut.wait();
std::cout << "\n194232491 ";
if (fut.get()) // guaranteed to be ready (and not block) after wait returns
std::cout << "is prime.\n";
else
std::cout << "is not prime.\n";
return 0;
}
- wait_for / wait_util
和wait一样
// future::wait_for
#include <iostream> // std::cout
#include <future> // std::async, std::future
#include <chrono> // std::chrono::milliseconds
// a non-optimized way of checking for prime numbers:
bool is_prime (int x) {
for (int i=2; i<x; ++i) if (x%i==0) return false;
return true;
}
int main ()
{
// call function asynchronously:
std::future<bool> fut = std::async (is_prime,700020007);
// do something while waiting for function to set future:
std::cout << "checking, please wait";
std::chrono::milliseconds span (100);
while (fut.wait_for(span)==std::future_status::timeout)
std::cout << '.';
bool x = fut.get();
std::cout << "\n700020007 " << (x?"is":"is not") << " prime.\n";
return 0;
}
2.2 shared_future
- 与future不同的是,可以被赋值,可以多个shared_future共享一个shared state,shared state的值可以被获取多次。
- get
和future一样,只不过当shared state可用时,不会释放shared state。
3.其他类型
3.1 launch
- 设置async的策略
enum class launch;
- launch::async
新建一个线程调用该函数,并在访问shared state对返回值进行同步。 - launch::deferred(延迟调用)
在访问shared state时才创建线程调用函数(get或wait)。
// launch::async vs launch::deferred
#include <iostream> // std::cout
#include <future> // std::async, std::future, std::launch
#include <chrono> // std::chrono::milliseconds
#include <thread> // std::this_thread::sleep_for
void print_ten (char c, int ms) {
for (int i=0; i<10; ++i) {
std::this_thread::sleep_for (std::chrono::milliseconds(ms));
std::cout << c;
}
}
int main ()
{
std::cout << "with launch::async:\n";
std::future<void> foo = std::async (std::launch::async,print_ten,'*',100);
std::future<void> bar = std::async (std::launch::async,print_ten,'@',200);
// async "get" (wait for foo and bar to be ready):
foo.get();
bar.get();
std::cout << "\n\n";
std::cout << "with launch::deferred:\n";
foo = std::async (std::launch::deferred,print_ten,'*',100);
bar = std::async (std::launch::deferred,print_ten,'@',200);
// deferred "get" (perform the actual calls):
foo.get();
bar.get();
std::cout << '\n';
return 0;
}
with launch::async:
*@**@**@**@**@*@@@@@
with launch::deferred:
**********@@@@@@@@@@
3.2 future_status
ready / timeout / deffered
3.3 future_errc
broken_promise/ future_already_retrieved /promise_already_satisfied/ no_state
3.4 future_error 异常类
- 继承自logic_error
class future_error : public logic_error;
4.函数Providers——async
- 调用fn,不等待fn执行完成,直接返回
函数返回值可以通过future对象读取(future::get)
//unspecified policy (1)
template <class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type>
async (Fn&& fn, Args&&... args);
//specific policy (2)
template <class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type>
async (launch policy, Fn&& fn, Args&&... args);
5.函数future_category
const error_category& future_category() noexcept;
// std::future_category example:
#include <iostream> // std::cerr
#include <future> // std::promise, std::future_error, std::future_category
int main ()
{
std::promise<int> prom;
try {
prom.get_future();
prom.get_future(); // throws a std::future_error of the future category
}
catch (std::future_error& e) {
if (e.code().category() == std::future_category())
std::cerr << "future_error of the future category thrown\n";
}
return 0;
}