get_future
与一个future对象相关联。函数调用后两个对象共享同一个共享状态。功能函数:
promise对象:异步的提供者(provider),在某个时候为共享状态(share state)设值。
future对象:异步的接收者,获取共享状态的值,必要时需要等待数据就绪。
示例:
// promise example
#include // std::cout
#include // std::ref
#include // std::thread
#include // 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> 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
(1). 默认构造
构建一个promise对象,与一个空的共享对象相关联。
(2). 带分配器的构造
和(1)相同,但是用alloc
为共享状态分配内存。
(3). 复制构造
禁用复制构造函数,promise对象不可被复制。
(4). 移动构造
对象获取x的共享状态,此后x等同于(1)。
示例:
// promise constructors
#include // std::cout
#include // std::ref
#include // std::allocator, std::allocator_arg
#include // std::thread
#include // 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);
th.join();
return 0;
}
输出:
value: 20
(1). 获取 rhs 的共享状态。原有的共享状态被丢弃(如同promise对象被销毁)。rhs失去共享状态,等同于默认构造,任何尝试访问其共享状态的操作都会被抛出future_error异常,异常类型为no_state。
(2). promise对象不可复制。
示例:
// promise::operator=
#include // std::cout
#include // std::thread
#include // std::promise, std::future
std::promise<int> prom;
void print_global_promise () {
std::future<int> fut = prom.get_future();
int x = fut.get();
std::cout << "value: " << x << '\n';
}
int main ()
{
std::thread th1 (print_global_promise);
prom.set_value (10);
th1.join();
prom = std::promise<int>(); // reset, by move-assigning a new promise
std::thread th2 (print_global_promise);
prom.set_value (20);
th2.join();
return 0;
}
输出:
value: 10
value: 20
(1). 将val存入共享状态中,然后共享状态就绪。如果此时相关联的future对象正在等待数据(调用future.get
),取消线程阻塞并返回val
(2). void特殊化成员函数,单纯令共享状态处于就绪,不设置任何值。
(1). 将val存入共享状态中,线程退出时使其就绪。如果此时相关联的future对象正在等待数据(调用future.get
),那么等待线程会一直阻塞,直到前面的线程退出,共享状态就绪,future获取值val。调用该函数后共享状态已被赋值,若在线程退出之前尝试修改共享状态就会抛出future_error异常,异常类型为 promise_already_satisfied。
(2). void特殊化成员函数,单纯令共享状态处于就绪,不设置任何值。
将异常p存入共享状态,然后共享状态就绪。如果此时相关联的future对象正在等待数据(调用future.get
),取消线程阻塞并返回异常p。
示例:
// promise::set_exception
#include // std::cin, std::cout, std::ios
#include // std::ref
#include // std::thread
#include // std::promise, std::future
#include // 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;
}
输出:
Please enter an integer value: boogey!
[exception caught: ios_base::failbit caught]
将异常p存入共享状态中,线程退出时使其就绪。如果此时相关联的future对象正在等待数据(调用future.get
),那么等待线程会一直阻塞,直到前面的线程退出,共享状态就绪,future获取异常p。调用该函数后共享状态已被赋值,若在线程退出之前尝试修改共享状态就会抛出future_error异常,异常类型为 promise_already_satisfied。
promise对象与x交换共享状态。
等同于x.swap(y)
。
packaged_task用来包装一个可调用元素,供异步访问。它类似于std::function,不同的是它会自动向future对象传递数据。
packaged_task对象包含两个元素:
A. 存储任务(stored task)。一个可调用对象(例如函数指针,指向成员或者函数对象的指针),接受Args中的参数并返回Ret类型的值。
B. 共享状态(shared state)。存储A的返回结果(Ret类型),可通过future异步访问。
packaged_task对象的共享状态可以通过调用get_future
与一个future对象相关联。函数调用后两个对象共享同一个共享状态。共享状态的生存周期持续到与之关联的最后一个对象释放它或者被销毁。
功能函数:
packaged_task对象:异步的提供者(provider),在某个时候为共享状态(share state)设值。
future对象:异步的接收者,获取共享状态的值,必要时需要等待数据就绪。
示例:
// packaged_task example
#include // std::cout
#include // std::packaged_task, std::future
#include // std::chrono::seconds
#include // std::thread, std::this_thread::sleep_for
// count down taking a second for each value:
int countdown (int from, int to) {
for (int i=from; i!=to; --i) {
std::cout << i << '\n';
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Lift off!\n";
return from-to;
}
int main ()
{
std::packaged_task<int(int,int)> tsk (countdown); // set up packaged_task
std::future<int> ret = tsk.get_future(); // get future
std::thread th (std::move(tsk),10,0); // spawn thread to count down from 10 to 0
// ...
int value = ret.get(); // wait for the task to finish and get result
std::cout << "The countdown lasted for " << value << " seconds.\n";
th.join();
return 0;
}
输出:
10
9
8
7
6
5
4
3
2
1
Lift off!
The countdown lasted for 10 seconds.
(1). 默认构造
构造一个packaged_task对象,没有共享状态(share state)和存储任务(stored task)。
(2). 初始化构造
构造一个packaged_task对象,开辟一个共享状态,存储任务初始化为fn。
(3). 带分配器的初始化构造
和(2)相同,但是使用alloc
来分配内存。
(4). 复制构造 [禁用]
禁用复制构造函数,packaged_task对象不可复制。
(5). 移动构造
构造的对象获得x的共享状态,x的存储任务也被转移,x变成状态(1)。
示例:
// packaged_task construction / assignment
#include // std::cout
#include // std::move
#include // std::packaged_task, std::future
#include // 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;
}
输出:
The double of 10 is 20.
(1). ackaged_task对象获取 rhs 的共享状态和存储任务。在获取之前,对象先抛弃原有的共享状态(如同packaged_task对象被销毁)。此后 rhs 不再拥有共享状态,所有试图访问其共享状态的操作都会导致 future_error 异常报出,异常类型为 no_state 。
(2). ackaged_task对象不可复制。
检查packaged_task当前是否有关联的共享状态。对于默认构造的packaged_task对象,函数返回false(除非被移动赋值或者被交换了)。
示例:
// packaged_task::valid
#include // std::cout
#include // std::move
#include // std::packaged_task, std::future
#include // std::thread
// function that launches an int(int) packaged_task in a new thread:
std::future<int> launcher (std::packaged_task<int(int)>& tsk, int arg) {
if (tsk.valid()) {
std::future<int> ret = tsk.get_future();
std::thread (std::move(tsk),arg).detach();
return ret;
}
else return std::future<int>();
}
int main ()
{
std::packaged_task<int(int)> tsk ([](int x){return x*2;});
std::future<int> fut = launcher (tsk,25);
std::cout << "The double of 25 is " << fut.get() << ".\n";
return 0;
}
输出:
The double of 25 is 50.
返回一个与该packaged_task对象的共享状态相关联的future对象。该future可以获取packaged_task对象在共享状态中设置的值或者异常。每个packaged_task对象只匹配唯一的一个future对象。函数调用以后,packaged_task需要通过调用其存储任务使其共享状态就绪,否则它会自动存储 future_error 异常,为销毁做好准备,异常类型为 broken_promise 。
示例:
// packaged_task::get_future
#include // std::cout
#include // std::move
#include // std::packaged_task, std::future
#include // 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(); // 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.
调用存储任务,args为其传入参数。如果存储任务调用成功,任务返回值存入共享状态中;如果存储任务调用失败,抛出异常存入到共享状态中。这两种情况都会使存储状态就绪,阻塞线程(如果有)被唤醒。获取共享状态数据前,需要先获取future对象(get_future
),然后通过future对象的get
函数获取数据.
存储任务通常在packaged_task构造的时候确定,调用效果取决于该任务的类型:(没理解)
The stored task is generally specified on construction. The effects of calling it depend on its type:
和std::promise::set_value_at_thread_exit
一个道理。
新建一个共享状态替换packaged_task对象的共享状态,原有的共享状态被舍弃(如同packaged_task对象被销毁)。存储任务保持不变,此后存储任务可以被再次调用。系统内部等同于用std::packaged_task::operator=
构建了一个新的packaged_task对象(存储任务不变)。
示例:
// packaged_task::reset
#include // std::cout
#include // std::move
#include // std::packaged_task, std::future
#include // 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;
}
输出:
The triple of 33 is 99.
The triple of 99 is 297.
对象与 x 交换共享状态和存储任务。
等同于x.swap(y)
。
(1). 在某个时候调用 fn (以 args 作为参数),不等 fn 执行完成就可返回。返回结果为一个future对象,可以通过future::get
获得 fn 的返回值。
(2). 该版本允许调用者自定义启动策略,版本(1)默认的自动选择,如同以 launch::async|launch::deferred 的启动策略运行版本(2)。
函数临时存储在共享状态中,要么是线程处理句柄使用的共享状态,要么是 fn 和 args(如同推迟函数deferred function)衰变副本中的共享状态,两种情况下共享状态都没有就绪。一旦 fn 运行结束,共享状态存入 fn 的返回值并就绪。(没理解)
The function temporarily stores in the shared state either the threading handler used or decay copies of fn and args (as a deferred function) without making it ready. Once the execution of fn is completed, the shared state contains the value returned by fn and is made ready.
启动策略:
std::future::wait
或者std::future::get
被调用)。此时,fn 被调用,不再处于“推迟”状态。fn 返回后,future对象的共享状态就绪。函数返回:
返回一个future对象,当 fn 执行结束后,future对象的共享状态就绪。
在 launch::async 模式下,线程创建成功就返回future对象,即使该对象的共享状态从未被访问:在这种情况下,随着 fn 的返回,future对象同步销毁。因此,即使 fn 返回void,异步行为也不能忽略返回值。
示例:
// async example
#include // std::cout
#include // std::async, std::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对象或程序中获取数据,如果在不同的线程中,则正确同步此访问,借此实现线程间的通信。
我们称一个与共享状态想关联的future对象为“有效的”(valid),这种对象可以通过以下方式获得:
async
promise::get_future
packaged_task::get_future
只有“有效的”future对象才有作用,默认构造的future对象就不是“有效的”(除非被一个“有效的”future对象移动赋值)。
通过对一个“有效的”的future对象调用future::get
来获取共享数据。如果此时provider的共享状态已就绪(通过向其中写入值或者异常),则返回共享数据;如果还未就绪,调用线程阻塞,直到provider的共享状态就绪。通过这种方法实现两个线程之间的同步。
共享状态的生存周期持续到与之关联的最后一个对象释放它或者被销毁。
// future example
#include // std::cout
#include // std::async, std::future
#include // 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,444444443);
// 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 << '.' << std::flush;
bool x = fut.get(); // retrieve return value
std::cout << "\n444444443 " << (x?"is":"is not") << " prime.\n";
return 0;
}
输出(时间不尽相同):
checking, please wait........................
444444443 is prime.
(1). 默认构造
创建一个空的future对象:无共享状态,所以不是“有效的”,但是可以被另一个“有效的”future对象移动赋值。
(2). 复制构造 [禁用]
禁用复制构造函数,future对象不可复制。(可复制的future对象见shared_future)
(3). 移动构造
获取 x 的共享状态,x 失去共享状态,状态变成(1)。
示例:
// future::future
#include // std::cout
#include // std::async, std::future
int get_value() { return 10; }
int main ()
{
std::future<int> foo; // default-constructed
std::future<int> bar = std::async (get_value); // move-constructed
int x = bar.get();
std::cout << "value: " << x << '\n';
return 0;
}
输出:
value: 10
(1). 获取 rhs 的的共享状态。如果调用以前该对象是”有效的“,它会断开与之前共享状态的关联,如果之前的共享状态只与该对象关联,断开连接后之前的共享状态自行销毁。调用之后 rhs 失去共享状态,等同于默认构造的future对象,不再是“有效的”。
(2). future对象不可复制。
示例:
// future::operator=
#include // std::cout
#include // 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;
}
输出:
value: 10
返回一个shared_future对象,它获得该future对象(*this)的共享状态,future对象失去共享状态变成默认构造状态,不再是“有效的”。
示例:
// future::share
#include // std::cout
#include // std::async, std::future, std::shared_future
int get_value() { return 10; }
int main ()
{
std::future<int> fut = std::async (get_value);
std::shared_future<int> shfut = fut.share();
// shared futures can be accessed multiple times:
std::cout << "value: " << shfut.get() << '\n';
std::cout << "its double: " << shfut.get()*2 << '\n';
return 0;
}
输出:
value: 10
its double: 20
在共享状态就绪的时候返回其存储的值或者异常。若共享状态此时还未就绪,函数会阻塞调用线程直到共享状态就绪。一旦就绪,函数会唤醒阻塞线程,并返回共享状态中的数据。此后future对象将不再是“有效的”:对于每个共享状态该函数最多调用一次。线程的同步分别发生在共享状态的就绪和函数返回两处。
版本(3)是void特殊化版本,函数不返回任何数据,但还是要等到共享状态就绪再释放它。
示例:
// future::get
#include // std::cout, std::ios
#include // std::async, std::future
#include // std::exception
int get_int() {
std::cin.exceptions (std::ios::failbit); // throw on failbit set
int x;
std::cin >> x; // sets failbit if invalid
return x;
}
int main ()
{
std::future<int> fut = std::async (get_int);
std::cout << "Please, enter an integer value: ";
try {
int x = fut.get();
std::cout << "You entered: " << x << '\n';
}
catch (std::exception&) {
std::cout << "[exception caught]";
}
return 0;
}
输出:
Please, enter an integer value: 101
You entered: 101
检测当前future对象是否“有效的”(有关联的共享状态)。当future对象是默认构造(且未被移动赋值),或者已调用过一次future::get函数(且未被移动赋值),返回false。
示例:
// future::valid
#include // std::cout
#include // std::async, std::future
#include // std::move
int get_value() { return 10; }
int main ()
{
std::future<int> foo,bar;
foo = std::async (get_value);
bar = std::move(foo);
if (foo.valid())
std::cout << "foo's value: " << foo.get() << '\n';
else
std::cout << "foo is not valid\n";
if (bar.valid())
std::cout << "bar's value: " << bar.get() << '\n';
else
std::cout << "bar is not valid\n";
return 0;
}
输出:
foo is not valid
bar's value: 10
等待共享状态就绪。若共享状态此时还未就绪,函数会阻塞调用线程直到共享状态就绪。一旦就绪,函数会唤醒阻塞线程,然后直接返回,不获取共享状态中的数据。线程的同步分别发生在共享状态的就绪和函数返回两处。
示例:
// future::wait
#include // std::cout
#include // std::async, std::future
#include // 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;
}
输出:
checking...
194232491 is prime.
和std::future::wait基本相同,只是加了时间段(rel_time)限制。
若未就绪的共享状态具有推迟功能(例如以 launch::deferred 模式调用async
返回的future),函数不阻塞线程,而是直接返回 future_status::deferred 。
// future::wait_for
#include // std::cout
#include // std::async, std::future
#include // 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;
}
输出(时间不尽相同):
checking, please wait..........................................
700020007 is prime.
和std::future::wait_for 基本相同,时间段(rel_time)换成了时间点(abs_time)。
shared_future和future功能基本一样,shared_future相比future主要有以下几点区别:
[1]. http://www.cplusplus.com/reference/future/