|
|
定义于头文件 |
||
template< class R > class promise; |
空模板 | (C++11 起) |
template< class R > class promise |
非 void 特化,用于在线程间交流对象 | (C++11 起) |
template<> class promise |
void 特化,用于交流无状态事件 | (C++11 起) |
类模板 std::promise
提供存储值或异常的设施,之后通过 std::promise
对象所创建的 std::future 对象异步获得结果。注意 std::promise
只应当使用一次。
每个 promise 与共享状态关联,共享状态含有一些状态信息和可能仍未求值的结果,它求值为值(可能为 void )或求值为异常。 promise 可以对共享状态做三件事:
promise 是 promise-future 交流通道的“推”端:存储值于共享状态的操作同步于(定义于 std::memory_order )任何在共享状态上等待的函数(如 std::future::get )的成功返回。其他情况下对共享状态的共时访问可能冲突:例如, std::shared_future::get 的多个调用方必须全都是只读,或提供外部同步。
default (1) | |
默认构造函数,初始化一个空的共享状态 |
---|---|---|
with allocator (2) | |
带自定义内存分配器的构造函数,与默认构造函数类似,但是使用自定义分配器来分配共享状态 |
copy [deleted] (3) | |
拷贝构造函数,被禁用 |
move (4) | |
移动构造函数 |
#include
#include
#include
#include
#include
#include
void accumulate(std::vector::iterator first,
std::vector::iterator last,
std::promise accumulate_promise)
{
int sum = std::accumulate(first, last, 0);
accumulate_promise.set_value(sum); // 提醒 future
}
void do_work(std::promise barrier)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
barrier.set_value();
}
int main()
{
// 演示用 promise 在线程间传递结果。
std::vector numbers = { 1, 2, 3, 4, 5, 6 };
std::promise accumulate_promise;
std::future accumulate_future = accumulate_promise.get_future();
std::thread work_thread(accumulate, numbers.begin(), numbers.end(),
std::move(accumulate_promise));
// future::get() 将等待直至该 future 拥有合法结果并取得它
// 无需在 get() 前调用 wait()
//accumulate_future.wait(); // 等待结果
std::cout << "result=" << accumulate_future.get() << '\n';
std::cout << "我应该在result之后 " << std::endl;
work_thread.join(); // wait for thread completion
// 演示用 promise 在线程间对状态发信号
std::promise barrier;//使用void特化版本
std::future barrier_future = barrier.get_future();
std::thread new_work_thread(do_work, std::move(barrier));
barrier_future.wait();
new_work_thread.join();
return system("pause");
}
std::packaged_task 包装一个可调用的对象,并且允许异步获取该可调用对象产生的结果,从包装可调用对象意义上来讲,std::packaged_task 与 std::function 类似,只不过 std::packaged_task 将其包装的可调用对象的执行结果传递给一个 std::future 对象(该对象通常在另外一个线程中获取 std::packaged_task 任务的执行结果)。
std::packaged_task 对象内部包含了两个最基本元素,一、被包装的任务(stored task),任务(task)是一个可调用的对象,如函数指针、成员函数指针或者函数对象,二、共享状态(shared state),用于保存任务的返回值,可以通过 std::future 对象来达到异步访问共享状态的效果。
default (1) | packaged_task() noexcept; |
默认构造函数,初始化一个空的共享状态,并且该 packaged_task 对象无包装任务 |
---|---|---|
initialization (2) | template |
初始化一个共享状态,并且被包装任务由参数 fn 指定 |
with allocator (3) | template |
带自定义内存分配器的构造函数,与默认构造函数类似,但是使用自定义分配器来分配共享状态 |
copy [deleted] (4) | packaged_task (const packaged_task&) = delete; |
拷贝构造函数,被禁用 |
move (5) | packaged_task (packaged_task&& x) noexcept; |
移动构造函数 |
#include
#include
using namespace std;
int add(int x, int y)
{
cout << "add(x,y)" << " thread_id: "<< this_thread::get_id() << endl;
return x + y;
}
int f(int x, int y)
{
cout << "f(x,y)" << " thread_id: " << this_thread::get_id() << endl;
return std::pow(x,y);
}
void task_thread()
{
packaged_task task(add);
future fu = task.get_future();
thread task_td(std::move(task),20,34);
task_td.join();
cout << "res= " << fu.get() << " task_thread thread_id: " << this_thread::get_id() << endl;
}
void task_lambda()
{
packaged_task task([](int a, int b) { return a + b; });
future res = task.get_future();
task(2,9);
cout << "task_lambda " << this_thread::get_id() << endl;
}
void task_bind()
{
packaged_task task(bind(f,4,5));//C++11 bind的用法
future res = task.get_future();
task();
cout << " task_bind " << this_thread::get_id() << endl;
}
/*
* 类模板 std::packaged_task 包装任何可调用 (Callable) 目标(函数、 lambda 表达式、 bind 表达式或其他函数对象),
* 使得能异步调用它。其返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。
*/
int main()
{
task_thread();
task_lambda();
task_bind();
cout << "main thread id: " << this_thread::get_id() << endl;
return system("pause");
}
输出结果:
valid |
检查任务对象是否拥有合法函数 (公开成员函数) |
swap |
交换二个任务对象 (公开成员函数) |
获取结果 |
|
get_future |
返回与承诺的结果关联的 std::future (公开成员函数) |
执行 |
|
operator() |
执行函数 (公开成员函数) |
make_ready_at_thread_exit |
执行函数,并确保结果仅在一旦当前线程退出时就绪 (公开成员函数) |
reset |
重置状态,抛弃任何先前执行的存储结果 (公开成员函数) |
1. std::packaged_task::valid 和 std::packaged_task::get_future的使用
valid 检查当前 packaged_task 是否和一个有效的共享状态相关联,对于由默认构造函数生成的 packaged_task 对象,该函数返回 false,除非中间进行了 move 赋值操作或者 swap 操作。
get_future返回一个与 packaged_task 对象共享状态相关的 future 对象。返回的 future 对象可以获得由另外一个线程在该 packaged_task 对象的共享状态上设置的某个值或者异常。
void launcher(packaged_task& task, int x)
{
if (task.valid()) //检查任务对象是否拥有合法函数
{
future res = task.get_future();
thread t1(std::move(task),x);
t1.join();
cout << " launcher res: " << res.get() << endl;
}
}
2. std::packaged_task::operator()(Args... args) 的使用
调用该 packaged_task 对象所包装的对象(通常为函数指针,函数对象,lambda 表达式等),传入的参数为 args. 调用该函数一般会发生两种情况:
以上两种情况都使共享状态的标志变为 ready,因此其他等待该共享状态的线程可以获取共享状态的值或者异常并继续执行下去;共享状态的值可以通过在 future 对象(由 get_future获得)上调用 get 来获得。由于被包装的任务在 packaged_task 构造时指定,因此调用 operator() 的效果由 packaged_task 对象构造时所指定的可调用对象来决定:
void task_lambda()
{
packaged_task task([](int a, int b) { return a + b; });
future res = task.get_future();
task(2,9);
cout << "task_lambda " << this_thread::get_id() << endl;
}
3. make_ready_at_thread_exit的使用
该函数会调用被包装的任务,并向任务传递参数,类似 std::packaged_task 的 operator() 成员函数。但是与 operator() 函数不同的是,make_ready_at_thread_exit 并不会立即设置共享状态的标志为 ready,而是在线程退出时设置共享状态的标志。如果与该 packaged_task 共享状态相关联的 future 对象在 future::get 处等待,则当前的 future::get 调用会被阻塞,直到线程退出。而一旦线程退出,future::get 调用继续执行,或者抛出异常。
4. std::packaged_task::reset
重置 packaged_task 的共享状态,但是保留之前的被包装的任务
int print(int x)
{
return x*x;
}
int main()
{
packaged_task task(print);
future result = task.get_future();
task(100);
cout << "task reslut: " << result.get() << endl;
task.reset();
result = task.get_future();
thread t2(std::move(task),200);
t2.join();
cout << "t1 reslut: " << result.get() << endl;
return system("pause");
}
以上参考: