- providers future 和 智能指針有點類似
future對應(yīng)智能指針;
providers對應(yīng)智能指針指向的存儲區(qū)域;
當所有與shared state關(guān)聯(lián)的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對象才會被析構(gòu)
- 構(gòu)造函數(shù)如下
//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對象共享狀態(tài)的future 對象。
當該函數(shù)調(diào)用時,promise承諾在未來某個時間點(通過設(shè)置值或者異常)使它的共享狀態(tài)可用。
當設(shè)置好值或異常時,future對象就可以獲取該共享狀態(tài)的值。
future<T> get_future();
- set_value
在共享狀態(tài)里存儲值,此時shared state變?yōu)榭捎谩?br> 如果此時有一個future對象正在等待此狀態(tài)可用(調(diào)用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
只不過將值變?yōu)榱薳xception。其他過程跟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
設(shè)置值后不會立馬將shared state變?yōu)榭捎?,要直到線程退出時才可用。
在設(shè)置值到線程退出期間,任何修改此shared state值的操作都會拋出錯誤promise_already_satisfied。 - set_exception_at_thread_exit
類似
1.2 packaged_task——同步機制和promise一致
- packaged_task封裝一個可調(diào)用的對象,其返回值可以被獲取。
- 包含兩個元素
1)一個任務(wù)。是一個可調(diào)用對象(函數(shù)指針、函數(shù)對象指針),調(diào)用簽名(call signature):參數(shù)類型是Args,返回Ret類型。
2)一個共享狀態(tài)shared state。存儲調(diào)用任務(wù)的結(jié)果,可以被future獲取。
template <class T> packaged_task; // undefined
template <class Ret, class... Args> class packaged_task<Ret(Args...)>;
- 構(gòu)造函數(shù)
//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對象的任務(wù)被調(diào)用時,shared state會被設(shè)置值或異常,此時future就可以獲取該值。 - make_ready_at_thread_exit——也是調(diào)用運算符
類似于operator(),在線程退出設(shè)置shared state可用。跟promise相應(yīng)的成員函數(shù)類似
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對象關(guān)聯(lián)到shared state,在調(diào)用如下函數(shù)時被構(gòu)造:
1)async
2)promise::get_future
3)packaged_task::get_future - 在一個有效的future對象上調(diào)用futuer::get會阻塞其線程,直到provider讓shared state變得可用(設(shè)置值或者異常)。
- 移動賦值
//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();
// 類似于采用移動構(gòu)造函數(shù)
shared_future<T>(std::move(*this)
get
如果shared state不可用時,阻塞等待。
可用時,線程解除阻塞,返回并釋放shared state。使得future對象變?yōu)闊o效。
該函數(shù)對每個future shared state只能調(diào)用一次。valid
檢查future對象是否和shared state關(guān)聯(lián)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
- 設(shè)置async的策略
enum class launch;
- launch::async
新建一個線程調(diào)用該函數(shù),并在訪問shared state對返回值進行同步。 - launch::deferred(延遲調(diào)用)
在訪問shared state時才創(chuàng)建線程調(diào)用函數(shù)(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.函數(shù)Providers——async
- 調(diào)用fn,不等待fn執(zhí)行完成,直接返回
函數(shù)返回值可以通過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.函數(shù)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;
}