《探索C++多线程》:future源码(一)
来源:互联网 发布:微信号人肉软件 编辑:程序博客网 时间:2024/05/20 19:16
在此之前的几篇文章分别介绍和分析了C++11.0标准库中支持多线程的几个头文件:<thread>、<mutex>、<condition_variable>。那么接下来乘热打铁,在这篇文章中将要分析的是:多线程的异步操作。
多线程的异步操作源码在头文件<future>中。我们先来看一看<future>中都定义了些什么类、函数:
classesfuturefuture_errorpackaged_task promiseshared_futureenum classesfuture_errcfuture_statuslaunchfunctionsasyncfuture_categoy
从上表中可以看出,<future>中提供的外部接口就有6个class,3个enum class,2个function,在这篇文章中,我们先来分析上表中 用颜色标记的几个接口,剩下的将在下一篇博文中进行分析。
std::future
future提供了用来访问异步操作结果的机制。当一个异步操作我们不可能马上获取操作结果时,就可以用同步等待的方式来获取,通过查询future的状态(future_status)来获取异步操作结果。
future的状态定义在future_status中,如下:
enum class future_status {ready,// 异步操作已完成,共享状态变为了readytimeout,// 异步操作超时,在规定时间内共享状态没有变为readydeferred// 异步操作还没开始,共享状态包含了一个deferred函数};
class future中提供了几个方法:get()、wait()、wait_for()、wait_until()。在介绍future之前,先来介绍一个函数:std::async。
std::async
返回future对象,其关联的异步状态管理一个函数对象。可能从概念上我们还把握不到什么,下面看一段代码:
#include <iostream> // std::cout#include <future> // std::async, std::futureusing namespace std;// 这是一个用于检验素数的函数bool is_prime(int x) { cout << "Calculating. Please, wait...\n"; for (int i = 2; i < x; ++i) { if (x % i == 0) { return false; } } return true;}int main(){ // 异步地调用函数is_prime(313222313) future<bool> fut = async(is_prime, 313222313); cout << "Checking whether 313222313 is prime.\n"; bool ret = fut.get(); // 等待is_prime返回 if (ret) { cout << "It is prime!\n"; } else { cout << "It is not prime.\n"; } return 0;}
我们从代码中看到,async关联了is_prime函数且传入参数为313222313,async返回一个关联了异步状态的future对象。在关联完is_prime函数后,便异步地执行main函数和is_prime函数(实际上就是两个线程了)。而is_prime的返回值,可以通过future对象(代码中的fut)的get()方法获取。这里注意,在main中调用fut.get(),如果is_prime函数已经执行完了,那么可以直接获取到其返回值;如果is_prime函数还没有执行完,那么将阻塞直到得到其返回值。
实际上,在std::async中的第一个参数可以设置关联函数的异步启动策略,可以设定如下:
future<bool> fut = async(luanch::async, is_prime, 313222313);// 1future<bool> fut = async(luanch::defered, is_prime, 313222313);// 2future<bool> fut = async(luanch::any, is_prime, 313222313);// 3future<bool> fut = async(luanch::sync, is_prime, 313222313);// 4其中这四种异步启动策略,定义如下 ,另外在后面会我也会讲解到。
// 异步启动的策略enum class launch {async = 0x1,// 异步启动,在调用std::async()时创建一个新的线程以异步调用函数,并返回future对象;deferred = 0x2,// 延迟启动,在调用std::async()时不创建线程,直到调用了future对象的get()或wait()方法时,才创建线程;any = async | deferred,// 自动,函数在某一时刻自动选择策略,这取决于系统和库的实现,通常是优化系统中当前并发的可用性sync = deferred};讲了这么多,我们现在来总结一下std::async:
1、异步接口std::async可以自动创建线程去调用线程函数,并返回一个std::future对象,能方便的获取线程的执行结果;
2、提供了函数的异步启动策略,可以延迟启动。
到此为止,我们再回过头来接着讲std::future,实际上,future对象的获取,可以通过以下三种办法得到:
1、async
2、promise::get_future
3、packaged_task::get_future
其中方法1,我们已经在std::async中接触过了,那么后面的方法2、3,将在讲解std::promise和std::package_task时会讲到。
接下来,我们继续分析std::future对象的几种方法:get()、wait()、wait_for()、wait_until()。
std::future::get()
1、当共享状态就绪时,返回值存放在共享状态中或抛出异常;
2、当共享状态尚未就绪,则将阻塞线程并等待,直到准备就绪;
3、一旦共享状态准备就绪,函数就不阻塞了,将会返回(或抛出)并释放共享状态,使future对象不再有效,即成员函数在每个future对象的共享状态下至多调用一次。
std::future::wait()
1、等待共享状态就绪。若共享状态尚未准备就绪,则将阻塞线程并等待,直到准备就绪;
2、一旦共享状态准备就绪,函数就不阻塞了,并返回其值(既不读取值,也不抛出异常)。
我们来看一个例子:
#include <iostream> // std::cout#include <future> // std::async, std::future#include <chrono> // std::chrono::millisecondsusing namespace std;bool is_prime (int x) { for (int i = 2; i < x; ++i) { if (x % i == 0) { return false; } } return true;}int main () { future<bool> fut = async (is_prime, 194232491); cout << "checking...\n"; fut.wait();// 等待共享状态就绪 cout << "\n194232491 "; if (fut.get()) // 由于wait()已保证了共享状态已经就绪,所以get()将不会阻塞 cout << "is prime.\n"; else cout << "is not prime.\n"; return 0;}std::future::wait_for()
1、在一定时间内等待共享状态就绪;
2、如果共享状态尚未就绪,则将阻塞线程并等待,直到就绪或经过设定的时间rel_time;
举个例子:
#include <iostream> // std::cout#include <future> // std::async, std::future#include <chrono> // std::chrono::millisecondsbool is_prime (int x) { for (int i = 2; i < x; ++i) { if (x % i == 0) { return false; } } return true;}int main () { future<bool> fut = async (is_prime, 700020007); cout << "checking, please wait"; chrono::milliseconds span (100); while (fut.wait_for(span) == future_status::timeout) { // 若超时,则继续wait_forcout << '.'; } bool x = fut.get(); // 此时能保证共享状态已经就绪,因此get()不会阻塞 cout << "\n700020007 " << (x ? "is" : "is not") << " prime.\n"; return 0;}std::future::wait_until()
1、等待共享状态就绪,直到指定的时间点到来;
2、如果共享状态尚未就绪,则将阻塞线程并等待,直到就绪或指定的时间点到来。
好了,以上就是std::future的用法了。另外,我们可以注意到,在上面的代码中用到了future_status::timeout来指示函数返回的原因,future_staus是一个enum class,其定义如下:
enum class future_status {ready,// 共享状态就绪timeout,// 超时deferred// 共享状态包含了延迟(std::async使用了参数std::launch::defered)};
- 《探索C++多线程》:future源码(一)
- 《探索C++多线程》:future源码(二)
- 《探索C++多线程》:thread源码(一)
- 《探索C++多线程》:mutex源码(一)
- 《探索C++多线程》:condition_variable源码(一)
- 《探索C++多线程》:thread源码(二)
- 《探索C++多线程》:mutex源码(二)
- 《探索C++多线程》:condition_variable源码(二)
- C#:多线程编程探索
- Future和FutureTask(多线程)
- java 多线程( Future Callable)
- Objective-C:探索block(一)
- 多线程-Future
- 多线程----Future
- 多线程 Future
- 译 -- Java 并发编程(多线程)一 | Callable and Future | CountDownLatch | Runable
- C3p0源码探索(一)之配置篇
- C3p0源码探索(一)之配置篇
- Git可视化教程——Git Gui的使用
- OS_CPU.H
- 山东省第二届ACM大学生程序设计竞赛 Sequence
- Ubuntu16.04如何安装Hadoop2.6.0(单机伪分布方式)
- 运算放大器基本电路分析
- 《探索C++多线程》:future源码(一)
- iOS内测平台fir.im,发布内测版本
- jquery-weui-1.0.1弹出popup层多次点击以后无法弹出层解决方法
- python的自动化测试模块
- jbdc
- 关于 RTOS 的选择
- 把秒或者毫秒转为小时分钟
- android studio一键生成快速开发实现语言国际化
- 第九届河南省程序设计大赛-NYOJ-307-宝物(瓶颈路 贪心)