c++ future庫

  • 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;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容