c++ future库

  • 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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342