c++基础语法之future,promise,async详细讲解-SurfaceFlinger学习必备c++知识

hi,粉丝朋友们:

背景

在开始学习SurfaceFlinger相关源码分析时候,发现也有大量的新语法,这里如果需要顺利看懂代码就不得不学习一些新版本c++基础语法。比如看到如下的drawLayers这个方法时候,当时trace中看到是有线程切换,这里代码我们看到是future和promise。
在这里插入图片描述

在这里插入图片描述trace可以看出来有线程切换和等待
在这里插入图片描述
为啥新版本要出现std::future和std::promise呢?
以前版本创建了线程以后,我们不能直接从thread.join()得到结果,必须定义一个变量,在线程执行时,对这个变量赋值,然后其他线程执行join()等待线程执行完成,再获取这个值,过程相对繁琐。
  thread库提供了future用来访问异步操作的结果。std::promise用来包装一个值将数据和future绑定起来,为获取线程函数中的某个值提供便利,取值是间接通过promise内部提供的future来获取的,也就是说promise的层次比future高。

future

官方解释参考地址:
https://legacy.cplusplus.com/reference/future/future/?kw=future
获取线程返回值的类std::future,用来访问异步操作的结果。因为异步操作需要时间,future并不能马上获取其结果,只能在未来某个时候获取期待值,因此被称为future。
可以通过同步等待的方式,通过查询future的状态(future_status),来获取异步操作的结果。

future_status状态有3种:
1)future_status::deferred 异步操作还没开始;
2)future_status::ready 异步操作已经完成;
3)future_status::timeout 异步操作超时;

获取future异步操作的结果,有4种方式:
1)get 等待异步结束并返回结果;
2)wait 只是等待异步操作结束,没有返回值;
3)wait_for 超时等待异步操作返回结果,注意这里的返回结果就是future_status
4)wait_until 等待达到指定的时间点,异步操作返回结果,常配合当前时间点 + 时间段来设置目标时间点;

平常开发中使用get最多,因为一般使用future是想要获取另一个线程的执行结果,一般不会单独使用这个future类,会结合async和promise一起使用

async

std::async,线程异步操作函数std::async,可用来创建异步task,其返回结果保存到future对象中。当需要取得异步结果时,调用future.get()即可。如果不关注结果,只是简单等任务完成,可以使用future.wait()
方法原型,查询地址https://legacy.cplusplus.com/

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

在这里插入图片描述参数解释如上图所示
第一个核心参数的launch参数,代表线程创建的策略
1)std::launch::async 调用async时就开始创建线程;
2)std::launch::deferred 延迟加载方式创建线程。调用async时不创建线程,直到调用了future的get或者wait,才创建线程。
默认情况都是情况1
第二个是线程执行方法函数
第三个代表执行线程函数时候需要传递的参数

案例如下:

// async example
#include <iostream>       // std::cout
#include <future>         // std::async, std::future
#include <sys/types.h>
#include <unistd.h>
using namespace std;
// a non-optimized way of checking for prime numbers:
bool is_prime (int x) {
  std::cout << "Calculating. Please, wait... thread Id = "<< gettid()<<endl;
  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 main thread Id = "<< gettid()<<endl;
  // ...

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

执行结果如下:
在这里插入图片描述明显看到这里的调用async后就有两个线程了,主线程也是要等到子线程执行完成后才可以进行执行

promise

Promise
A promise is an object that can store a value of type T to be retrieved by a future object (possibly in another thread), offering a synchronization point.

On construction, promise objects are associated to a new shared state on which they can store either a value of type T or an exception derived from std::exception.

This shared state can be associated to a future object by calling member get_future. After the call, both objects share the same shared state:
- The promise object is the asynchronous provider and is expected to set a value for the shared state at some point.
- The future object is an asynchronous return object that can retrieve the value of the shared state, waiting for it to be ready, if necessary.

The lifetime of the shared state lasts at least until the last object with which it is associated releases it or is destroyed. Therefore it can survive the promise object that obtained it in the first place if associated also to a future.

协助线程赋值的类std::promise,将数据和future绑定。在线程函数中,为外面传入的promise对象赋值,线程函数执行完毕后,就可以通过promise的future获取该值。

应用场景

小疑问:为啥有了future这个后还需要promise呢?
这个问题回答其实可以考虑一下future的获取,future都是需要几个固定的异步线程调用方式,比如async这种,但是很多时候不喜欢用这种异步方式,那么自然也就没办法获取future,所以为了future的获取更加灵活方便,就需要有这个promise对象。

主要方法有
在这里插入图片描述

重点介绍如下两个常用的
1)get_future
用于返回一个和promise相关联的future对象,返回的这个future对象就可以调用相关get方法来获取promise通过se_value方法设置的值
2)set_value
设置promise的对应值

案例代码

#include <iostream>       // std::cout
#include <functional>     // std::ref
#include <thread>         // std::thread
#include <future>         // std::promise, std::future
using namespace std;
void print_int (std::future<int>& fut) {
  cout<<"child thread  print_int"<<endl;
  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

  std::this_thread::sleep_for(std::chrono::seconds(1));
  cout<<"main thread  prom.set_value (10)"<<endl;
  prom.set_value (10);                         // fulfill promise
                                               // (synchronizes with getting the future)
  th1.join();
  return 0;
}

执行结果:
在这里插入图片描述
可以看到结果是子线程先打印了,执行到future.get会一直等待主线程进行set_value,才会继续往下执行,这里是不是相比前面async来说更加灵活,没有限制用啥多线程方式。

实战结合SurfaceFlinger剖析

构建好promise和对应future
在这里插入图片描述
主线程通过future的get进行等待子线程执行完成通过set_value
主线程等待:
在这里插入图片描述

子线程进行set_value部分

void SkiaGLRenderEngine::drawLayersInternal(
        const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
        const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
        base::unique_fd&& bufferFence) {
//省略
    resultPromise->set_value({NO_ERROR, std::move(drawFence)});
    return;
}

通过上面学习基础知识这个sf的这块代码看起来是不是很方便了,学习了个新c++语法立马就结合SurfaceFlinger源码部分实战分析

再次贴上perfetto、systrace来再次结合验证

在这里插入图片描述
更多framework干货请关注“千里马学框架”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值