《探索C++多线程》:future源码(二)
来源:互联网 发布:修改linux ip 编辑:程序博客网 时间:2024/05/16 19:53
接上一篇文章:《探索C++多线程》:future源码(一),在本文中将对std::promise、std::packaged_task进行分析。
std::promise
promise对象可以保存某一T类型的值,该值可以被future对象(可能在另一个线程中)获取,因此promise也提供了一种同步手段。
在构造时,promise对象与一个新的共享状态(通常是std::future)相关联,他们可以存储T类型的值或从std::exception派生的异常。共享状态可以通过调用成员get_future来与future相关联,调用后,两个对象共享同一个状态:
1、promise对象是异步的提供者,并在某一时刻为共享状态设置值;
2、future对象是异步返回共享状态的值,它可以获取异步状态的值(必要时阻塞等待状态就绪);
我们来看一个例子:
#include <iostream> // std::cout#include <functional> // std::ref#include <thread> // std::thread#include <future> // std::promise, std::futureusing namespace std;void print_int(future<int>& fut) { int x = fut.get(); // 阻塞获取,当在另一个线程中调用了promise::set_value()后,不再阻塞,并立即返回共享状态的值 cout << "value: " << x << '\n';}int main() { promise<int> prom; // 创建promise对象 future<int> fut = prom.get_future(); // 与future关联 thread th1(print_int, ref(fut)); // 将future对象传到一个线程中 prom.set_value(10); // 设置值 // 与future同步 th1.join(); getchar(); return 0;}在上述代码中,pormise对象调用get_future()方法,返回与之关联的future。
std::promise::get_future()
该方法返回一个与promise对象共享状态相关联的future对象,返回的future对象,可以通过promise对象来访问共享状态的值或异常,每个promise对象共享状态返回一个future对象。
调用了此方法后,promise对象将在某一时刻(通过设置值或异常)使共享状态准备就绪,否则,它将在自动析构包含future_error类型异常的情况下准备就绪。
std::promise::set_value()
设置共享状态的值,若一个future对象关联了同一共享状态,并且调用了future::get()来阻塞的获取值时,经调用promise::set_value()后将不再阻塞并返回一个值。
std::promise::set_value_at_thread_exit()
设置共享状态的值,但并不立即将共享状态的标志设置为ready;相反地,是在线程退出时设置为就绪状态。如果某个future对象与promise对象的共享状态相关联,并且该future对象正在调用get(),则会被阻塞,当线程退出时,不再阻塞并且返回共享状态的值。
std::packaged_task()
包装了一个可调用的目标,并且允许异步的获取其结果。与std::function类似,但其结果将自动的传递给future对象(可以在另一个线程中调用future::get()获取该结果)。
我们来看一个例子:
#include <iostream> // std::cout#include <future> // std::packaged_task, std::future#include <chrono> // std::chrono::seconds#include <thread> // std::thread, std::this_thread::sleep_forusing namespace std;// 被包装的函数:秒倒数计数int countdown(int from, int to) { for (int i = from; i != to; --i) { cout << i << '\n'; this_thread::sleep_for(chrono::seconds(1)); } cout << "Lift off!\n"; return from - to;}int main() { packaged_task<int(int, int)> tsk(countdown); // 建立 packaged_task future<int> ret = tsk.get_future(); // 获取 future 对象 thread th(move(tsk), 10, 0); // 启动从10到0向下计数的线程 int value = ret.get(); // 阻塞的等待任务结束,并获取返回值 cout << "The countdown lasted for " << value << " seconds.\n"; th.join(); return 0;}
packaged_task对象内部包含两个元素:
1、被包装的任务:如函数指针,指向成员或函数对象的指针;
2、存储共享状态:用于存储任务的返回值,可以通过future::get()来异步访问共享状态的值。
std::packaged_task::get_future()
我们来看一段代码:
#include <iostream> // std::cout#include <utility> // std::move#include <future> // std::packaged_task, std::future#include <thread> // std::threadusing namespace std;int triple (int x) { return x * 3;}int main () { packaged_task<int(int)> tsk (triple); // 包装任务 future<int> fut = tsk.get_future(); // 获取 future 对象 thread(move(tsk), 33).detach(); // 建立线程,并调用任务 int value = fut.get(); // 阻塞等待任务完成,并获取结果 cout << "The triple of 33 is " << value << ".\n"; return 0;}在上述代码中,主线程与任务线程剥离,任务线程交由系统管理,主线程调用fut.get()将阻塞地等待任务线程计算完毕,才能获取到共享状态的值。
std::packaged_task::reset()
同样的,我们来看一段代码:
#include <iostream> // std::cout#include <utility> // std::move#include <future> // std::packaged_task, std::future#include <thread> // std::threadusing namespace std;int triple(int x) { return x * 3;}int main() { packaged_task<int(int)> tsk(triple); future<int> fut = tsk.get_future(); tsk(33); cout << "The triple of 33 is " << fut.get() << ".\n"; // 再次使用同一个 packaged_task 对象 tsk.reset(); fut = tsk.get_future(); thread(move(tsk), 99).detach(); cout << "Thre triple of 99 is " << fut.get() << ".\n"; getchar(); return 0;}重置任务:在保持同一包装任务的同时,使用新的共享状态来重置任务对象,这允许再次调用存储任务。
- 《探索C++多线程》:future源码(二)
- 《探索C++多线程》:future源码(一)
- 《探索C++多线程》:thread源码(二)
- 《探索C++多线程》:mutex源码(二)
- 《探索C++多线程》:condition_variable源码(二)
- netty源码探索(二)
- 《探索C++多线程》:thread源码(一)
- 《探索C++多线程》:mutex源码(一)
- 《探索C++多线程》:condition_variable源码(一)
- Java多线程(二)——Callable、Future和FutureTask
- C#:多线程编程探索
- Future和FutureTask(多线程)
- java 多线程( Future Callable)
- netty5源码探索(二)----AbstractByteBuf
- 多线程-Future
- 多线程----Future
- 多线程 Future
- C# 多线程(二)
- 美食地图- 壹合先生的食堂
- linux 重定向
- 【服务器】腾讯云 Linux javaWeb服务器部署
- AD分辨率和精度区别
- 639UVa棋盘放车
- 《探索C++多线程》:future源码(二)
- 网络防火墙之iptables的前世今生和归宿
- android全屏/沉浸式状态栏下,各种键盘挡住输入框解决办法
- Centos 7 开放查看端口 防火墙关闭打开
- MySQL MHA高可用方案
- Binder子系统之调试分析(一)
- Url_Pattern
- I2C总线协议学习笔记
- Eventbus注册异常:its super classes have no public methods with the @Subscribe annotation