C++ 异步访问

和自甴很熟 提交于 2020-02-06 03:34:26

packaged_task

一个 packaged_task 包装了一个可调用对象,并且允许异步获取该可调用对象的结果

它重载了 operator() ,因此它也是一个可调用对象。

一个 packaged_task 对象包含两个部分:

  • stored task:就是一个可调用对象。
  • shared state:用于存储 stored task 的执行结果,且可以通过 future 异步访问之。

调用 get_future 成员函数之后,返回的 future 便与 shared state 建立关联。

shared state 会一直存在直到最后一个与之关联的对象释放了该关联,或该对象被销毁。

构造

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 (const packaged_task&) = delete;
move (5) packaged_task (packaged_task&& x) noexcept;

如,

std::packaged_task<int(int)> bar ([](int x){return x*2;}); // initialized

赋值

move (1) packaged_task& operator= (packaged_task&& rhs) noexcept;
copy [deleted] (2) packaged_task& operator= (const packaged_task&) = delete;

shared state 相关操作

future<Ret> get_future();

获取和 shared state 关联的 future 。

bool valid() const noexcept;

如果 packaged_task 当前与一个 shared state 关联,则返回 true 。

默认构造的 packaged_task 没有关联的 shared state 。

void reset();

让 packaged_task 与一个新的 shared state 关联。不改变 stored task 。

// packaged_task::get_future
#include <iostream>
#include <utility>
#include <future>
#include <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();   // get future

  std::thread(std::move(tsk),33).detach();   // spawn thread and call task

  // ...

  int value = fut.get();                     // wait for the task to complete and get result

  std::cout << "The triple of 33 is " << value << ".\n";

  return 0;
}
The triple of 33 is 99.
// packaged_task::reset
#include <iostream>
#include <utility>
#include <future>
#include <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;
}
The triple of 33 is 99.
The triple of 99 is 297.

其他操作

void operator()(Args... args);

使用 args 作为参数调用 stored task 。

void make_ready_at_thread_exit (args... args);

使用 args 作为参数调用 stored task ,但是让 shared state 在线程退出时才就绪,而不是一完成调用就让其就绪。

交换

成员函数 void swap (packaged_task& x) noexcept;
非成员函数 template <class Ret, class… Args> void swap (packaged_task<Ret(Args…)>& x, packaged_task<Ret(args…)>& y) noexcept;

交换两者的 stored task 和 shared state 。

promise

可以往一个 promise 对象中存储一个值,然后通过与其关联的 future 对象来获取该值。

一旦 promise 对象构造完成,它便关联有一个 shared state,其用于存储一个值或一个异常。

调用 get_future 成员函数之后,返回的 future 便与 shared state 建立关联。

shared state 会一直存在直到最后一个与之关联的对象释放了该关联,或该对象被销毁。

构造

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;

如,

std::promise<int> foo;
std::promise<int> bar = std::promise<int>(std::allocator_arg,std::allocator<int>());

赋值

move (1) promise& operator= (promise&& rhs) noexcept;
copy [deleted] (2) promise& operator= (const promise&) = delete;

shared state 相关操作

设置值

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
generic template (1) void set_value_at_thread_exit (const T& val);
<br.>void set_value_at_thread_exit (T&& val);
specializations (2) void promise<R&>::set_value_at_thread_exit (R& val); // when T is a reference type (R&)

void promise<void>::set_value_at_thread_exit (void); // when T is void

在线程退出时才让 shared state 就绪。

设置异常

void set_exception (exception_ptr p);

调用 future::get() 函数之后,将抛出 p 指向的异常。

void set_exception_at_thread_exit (exception_ptr p);

在线程退出时才让 shared state 就绪。

获取关联的 future

future<T> get_future();
// promise example
#include <iostream>
#include <functional>
#include <thread>
#include <future> 

void print_int (std::future<int>& fut) {
  int x = fut.get();
  std::cout << "value: " << x << '\n';
}

int main () {
  std::promise<int> prom;                      // create promise

  std::future<int> fut = prom.get_future();    // engagement with future

  std::thread th1 (print_int, std::ref(fut));  // send future to new thread

  prom.set_value (10);                         // fulfill promise
                                               // (synchronizes with getting the future)
  th1.join();
  return 0;
}
value: 10
// promise::set_exception
#include <iostream>
#include <functional>
#include <thread>
#include <future>
#include <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;
}
Please enter an integer value: boogey!
[exception caught: ios_base::failbit caught]

其他操作

交换

成员函数 void swap (promise& x) noexcept;
非成员函数 template <class T> void swap (promise<T>& x, promise<T>& y) noexcept;

交换两者的 shared state 。

async

用于异步调用一个可调用对象。

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);

在某个时间点调用 fn(args) 。

立即返回,不阻塞。

fn 的返回值通过 async 返回的 future 获取。

形式(1)等同于使用 launch::async|launch::deferred 作为 launce policy 。

policy 可取值如下:

policy description
launch::async Asynchronous: Launches a new thread to call fn (as if a thread object is constructed with fn and args as arguments, and accessing the shared state of the returned future joins it).
launch::deferred Deferred: The call to fn is deferred until the shared state of the returned future is accessed (with wait or get). At that point, fn is called and the function is no longer considered deferred. When this call returns, the shared state of the returned future is made ready.
launch::async|launch::deferred Automatic: The function chooses the policy automatically (at some point). This depends on the system and library implementation, which generally optimizes for the current availability of concurrency in the system.
// async example
#include <iostream>
#include <future>

// a non-optimized way of checking for prime numbers:
bool is_prime (int x) {
  std::cout << "Calculating. Please, wait...\n";
  for (int i=2; i<x; ++i) if (x%i==0) return false;
  return true;
}

int main () {
  // call is_prime(313222313) asynchronously:
  std::future<bool> fut = std::async (is_prime,313222313);

  std::cout << "Checking whether 313222313 is prime.\n";
  // ...

  bool ret = fut.get();      // waits for is_prime to return

  if (ret) std::cout << "It is prime!\n";
  else std::cout << "It is not prime.\n";

  return 0;
}
Checking whether 313222313 is prime.
Calculating. Please, wait...
It is prime!

future

用于访问一个 provider 对象中的值。

构造

default (1) future() noexcept;
copy [deleted] (2) future (const future&) = delete;
move (3) future (future&& x) noexcept;

赋值

move (1) future& operator= (future&& rhs) noexcept;
copy [deleted] (2) future& operator= (const future&) = delete;

获取值

检查 future 是否有效

bool valid() const noexcept;

如果 future 和 shared state 关联,则返回 true 。默认构造的 future 没有关联的 shared state 。

get

generic template (1) T get();
reference specialization (2) R& future<R&>::get(); // when T is a reference type (R&)
void specialization (3) void future<void>::get(); // when T is void

当 shared state 就绪时,获取 shared state 中的值/异常。

如果 shared state 还未就绪,则阻塞。

等待 shared state 就绪

void wait() const;

如果 shared state 还未就绪,则阻塞。

template <class Rep, class Period>
future_status wait_for (const chrono::duration<Rep,Period>& rel_time) const;

和 wait 类似,但是最多等待 rel_time 时长。

如果 shared state 包含一个 deferred 函数,则立即返回,不阻塞。

返回值如下:

value description
future_status::ready The shared state is ready: the producer has set a value or exception.
future_status::timeout The function waited for rel_time without the shared state becoming ready.
future_status::deferred The shared state contains a deferred function.
template <class Clock, class Duration>
future_status wait_until (const chrono::time_point<Clock,Duration>& abs_time) const;

和 wait_for 类似,只是以绝对时间指定超时时间。

// future::wait
#include <iostream>
#include <future>
#include <chrono>

// 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;
}
checking...
194232491 is prime.
// future::wait_for
#include <iostream>
#include <future>
#include <chrono>

// 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;
}

其他操作

shared_future<T> share();

返回一个 shared_future,该返回值会获取当前 future 的 shared state 。即,此函数过后,future 没有与 shared state 关联。

shared_future

和 future 类似,只是它允许拷贝,允许多个 shared_future 共享一个 shared state ,允许多次访问 shared state 中的值。

shared state 会一直保持有效,直到最后一个与之关联的对象释放该关联或该对象被销毁。

构造

default (1) shared_future() noexcept;
copy (2) shared_future (const shared_future& x);
move (3) shared_future (shared_future&& x) noexcept;
move from future (4) shared_future (future<T>&& x) noexcept;

赋值

move (1) shared_future& operator= (shared_future&& rhs) noexcept;
copy (2) shared_future& operator= (const shared_future& rhs);

获取值

检查 future 是否有效

bool valid() const noexcept;

如果 shared_future 和 shared state 关联,则返回 true 。默认构造的 shared_future 没有关联的 shared state 。

get

generic template (1) T get();
reference specialization (2) R& shared_future<R&>::get(); // when T is a reference type (R&)
void specialization (3) void shared_future<void>::get(); // when T is void

当 shared state 就绪时,获取 shared state 中的值/异常。

如果 shared state 还未就绪,则阻塞。

等待 shared state 就绪

void wait() const;

如果 shared state 还未就绪,则阻塞。

template <class Rep, class Period>
future_status wait_for (const chrono::duration<Rep,Period>& rel_time) const;

和 wait 类似,但是最多等待 rel_time 时长。

如果 shared state 包含一个 deferred 函数,则立即返回,不阻塞。

返回值如下:

value description
future_status::ready The shared state is ready: the producer has set a value or exception.
future_status::timeout The function waited for rel_time without the shared state becoming ready.
future_status::deferred The shared state contains a deferred function.
template <class Clock, class Duration>
future_status wait_until (const chrono::time_point<Clock,Duration>& abs_time) const;

和 wait_for 类似,只是以绝对时间指定超时时间。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!