当前位置: 首页 > news >正文

C++11 future、promise实现原理

前言

        针对异步调用实现,可以将整体任务分为两个部分:任务的提交和任务结果的获取。通过分离这两个部分可以将任务的执行阶段交给其他线程执行,对于一些耗时任务、阻塞任务来说会提升任务提交线程的任务处理能力。在C++11中提供了std::future 和 std::promise两种对象来实现上述需求。

一、双方关系

        对于future和promise的两者关系:future和promise中间维护了一个内存区域(共享状态),该区域是两方进行数据交互的“中间商”。针对一个异步实现过程中,首先有一个异步任务的创建方,也就是异步任务的提交者,它对应future,通过future提供的get方法可以获取异步调用的结果,即从共享状态区域中获取promise存入的数据内容。另一方为异步任务的执行方,它对应promise。通过promise内部对应的set_value方法可以将数据存入共享状态区域,待后续future获取异步任务执行结果。

        从英文含义来看,future:期待/期望 promise:承诺/诺言。future对象期待某些东西,promise会给future一个承诺,即回应他的期待。而共享状态作为promise向future所期待的兑现自己的承诺。

        两者关系图如下:

二、底层实现

​    对于future和promise的底层实现中,根据上图对共享状态有了一个了解。对于双方而言,promise和future之间通过共享状态实现异步信息的传递。该共享状态底层实现与shared_ptr的引用计数相同。当promise被创建之时,会创建一个关联状态对象(state),即共享状态。该关联状态对象内部的计数器初始值为0。此时创建一个future,其构造函数的入参需要一个关联状态对象指针来实现promise和future关联关系的建立。此时一个promise和future的关联关系建立完成。

​    对于future的get使用,future的get方法首先会创建一个unique_ptr指针管理future中的state变量,并创建一个临时指针指向state,然后将future中的state变量置为nullptr,最后返回值返回该临时变量的值,即state中的数据内容。如果此时的关联状态中promise还没添加数据,即此时的共享状态区域中还没有数据,会阻塞当前线程。对于数据是否准备好通过state的状态是否为ready状态判断。因此在使用get时需要注意,get取数据只能调用一次,如果连续调用get会出现异常。因为一个future需要绑定一个state,而当调用get时会取出之前绑定好的state中的数据内容,并将state置为nullptr,如果连续调用,此时state为nullptr就会返回异常。

​    对于promise的set_value使用,promise的set_value方法同理会先检查是否关联了一个state,如果未关联则抛出异常。正常的绑定则进行赋值操作。其中赋值操作可以使用左值版本也可以使用右值版本。对于set_value对state的具体操作为,首先创建一个unique_lock的临时对象上锁,然后判断当前state是否已经被赋值,如果已经赋值的话则抛出异常,如果未赋值则正常进行赋值。然后修改当前state状态为ready状态。最后调用state内部的条件变量,唤醒阻塞在当前state上的线程,即如果future提前进行get操作想要获取state中的数据会进入阻塞,此时promise进行state赋值后会唤醒future。

三、线程安全性

​    对于promise和future的线程安全性分析,应该从共享的部分入手,即state。对于state的使用是否线程安全就决定了future和promise是否线程安全。因此future和promise是线程安全的。

    更多资料:0voice · GitHub

http://www.lryc.cn/news/583696.html

相关文章:

  • 嵌入式调试LOG日志输出(以STM32为例)
  • 深度学习模型表征提取全解析
  • Spring Cloud Gateway 的路由和断言是什么关系?
  • 【TCP/IP】3. IP 地址
  • 【工具变量】上市公司企业金融强监管数据、资管新规数据(2001-2024年)
  • C++11 std::move与std::move_backward深度解析
  • 【PyTorch】PyTorch中torch.nn模块的全连接层
  • LeetCode经典题解:1、两数之和(Two Sum)
  • 小程序软装: 组件库开发
  • Python Day8
  • Ubuntu22.04 设置显示存在双屏却无法双屏显示
  • Mysql中的日志-undo/redo/binlog详解
  • spring-data-jpa + Alibaba Druid多数据源案例
  • 10.9 大模型训练数据优化实战:3步让准确率从68%飙升至79%
  • Debezium:一款基于CDC的开源数据同步工具
  • 深度学习 最简单的神经网络 线性回归网络
  • 桌面开发,在线%图书管理系统%开发,基于C#,winform,界面美化,mysql数据库
  • (八)PS识别:使用 Python 自动化生成图像PS数据集
  • 第十五天,7月9日,八股
  • 图像处理中的直方图均衡化:原理与实现
  • uniapp中使用uView-plus踩坑记录
  • 18-C#改变形参内容
  • 【linux】ssh使用-X参数后报错:X11 forwarding request failed on channel 0
  • Windows Subsystem for Linux (WSL):现代开发的终极跨平台方案
  • Ubuntu重装系统后ssh连接不上(遇到 ​​“Unit ssh.service not found“​​ 错误)
  • ServBay Windows 1.2.0 更新!新增 PHP 设置与 Ollama 支持
  • SpringGateway网关增加https证书验证
  • rt thread studio 和 KEIL对于使用rt thread 的中间件和组件,哪个更方便
  • 蛋白质序列-kappa参数计算算法解读
  • WPF使用WebBrowser 解决href标签target=_blank在浏览器窗口打开新链接而非窗体内部打开的问题