AUTOSAR_EXP_ARAComAPI的5章笔记(7)

5.3.6 Methods

对于远程服务提供的每种方法,Proxy Class都包含一个特定于该方法的包装类的成员。

在我们的示例中,有三种方法,相应的成员分别名为 Calibrate(类型为 methods::Calibrate)、Adjust(类型为 methods::Adjust)和 LogCurrentState(类型为 methods::LogCurrentState)。就像事件类一样,代理类所需的方法类是在一个特定的命名空间 methods 中生成的,而这个 methods 命名空间包含在代理命名空间内。代理中的方法成员用于调用我们的代理所连接的可能是远程服务实例所提供的方法。

让我们来看一下示例中生成的方法类 —— 在这里我们选取 Adjust 方法:

class Adjust {
public:/*** 对于所有的输出参数和非空返回参数* 会生成一个包含该非空返回值和/或输出参数的封闭结构体。*/struct Output {bool success;Position effective_position;};/*** \brief 此操作将会调用该方法。** 通过操作符,通信管理将会进行调用并返回一个 future(异步结果),它允许调用者获取方法的结果。** \param[in] target_position  参考服务描述。** \return 一个包含 Output 结构体的 future。*/ara::core::Future<Output> operator()(const Position &target_position);
};

所以这个方法包装类并不是那么复杂。它仅仅由两部分组成:一个内部结构(struct Output)定义,它汇总了该方法所有的输出(OUT )/ 输入输出(INOUT )参数;还有一个括号运算符重载,使类看起来像函数,用于调用服务方法。

该运算符将服务方法的所有输入(IN )/ 输入输出(INOUT )参数作为输入(IN)参数包含在内。这意味着在抽象服务方法描述中的输入输出(INOUT )参数在 ara::com API 中被拆分成一对输入(IN)和输出(OUT)参数。

对一个服务方法(不是 “单向方法”)调用的返回值是一个ara::core::Future,其中模板参数是内部结构的类型,这个内部结构汇总了该方法的所有输出(OUT )参数。在下一小节中将详细介绍这个 ara::core::Future

5.3.6.1 One-Way aka Fire-and-Forget Methods

在介绍“普通” 方法提供的功能之前,我们在此简要介绍一下 “单向方法”,其实,我们在上一节中已经提到了这个术语。 ara::com 支持一种特殊的方法,我们称之为 “单向(one-way)” 或 “发射后不管(fire-and-forget)”。从技术上讲,这是一种只有输入(IN)参数的方法 —— 没有输出(OUT)参数,并且不允许引发错误。也无法与服务器进行握手 / 同步!因此,客户端 / 调用者完全无法得知服务器 / 被调用者是否已经处理了 “单向” 调用。

在某些通信模式中,这种尽力而为的方法就完全足够了。在这种情况下,从资源的角度来看,这种 “单向 / 发射后不管” 的语义是非常轻量级的。如果我们查看这种方法的签名,我们会发现它比常规方法的签名更简单。

class LogCurrentState {
public:/*** \brief 此操作将会调用该方法。** 通过操作符,通信管理将会进行调用。** 这是一个单向(one - way)方法,所以不会提供任何反馈(返回值/输出参数)。*/void operator();
};
5.3.6.2 Event-Driven vs Polling access to method results

与上一节(5.3.5 小节)中描述的对事件数据的访问类似,我们也为基于事件驱动轮询的方法提供了 API 支持,以用于访问服务方法调用的结果。

这两种方法之间的区别的神奇之处在于返回的 ara::core::Futureara::core::Future 基本上是 C++11/C++14 std::future 类的扩展版本;详情见 [Specification of Adaptive Platform Core.pdf]

就像在事件数据访问中一样,这里的事件驱动意味着,一旦方法调用结果到达,方法的调用者(带有代理实例的应用程序)就会被 ara::com实现(Communication Management implementation)通知。

对于  ara::com实现来说,这意味着它必须在幕后设置某种等待机制(WaitEvent),一旦方法结果可用,该机制就会被唤醒,以通知 ara::com用户。那么 ara::core::Future 的不同使用模式是如何工作的呢?让我们更深入地了解一下我们的 ara::core::Future  及其提供的接口:

// 定义一个名为 future_status 的枚举类,基于无符号 8 位整数
enum class future_status : uint8_t
{ready,    // 表示共享状态已准备好timeout   // 表示在指定的超时时间过去之前,共享状态没有准备好
};// 定义一个模板类 Future,它接受类型参数 T 和类型参数 E(默认为 ErrorCode)
template <typename T, typename E = ErrorCode>
class Future
{
public:// 默认构造函数,使用 noexcept 修饰表示不会抛出异常Future() noexcept = default;// 析构函数~Future();// 禁用拷贝构造函数Future(const Future&) = delete;// 禁用拷贝赋值运算符Future& operator=(const Future&) = delete;// 移动构造函数,使用 noexcept 修饰表示不会抛出异常Future(Future&& other) noexcept;// 移动赋值运算符,使用 noexcept 修饰表示不会抛出异常Future& operator=(Future&& other) noexcept;/*** @brief 获取值** 此函数的行为应与相应的 std::future 函数相同** @returns 类型为 T 的值* @error 域:错误 通过 Promise::SetError 放入相应 Promise 中的错误**/T get();/*** @brief 获取结果** 与 get()类似,此调用会阻塞直到值或错误可用。不过,此调用永远不会抛出异常** @returns 包含值或错误的 Result* @error 域:错误 通过 Promise::SetError 放入相应 Promise 中的错误**/Result<T, E> GetResult() noexcept;/*** @brief 检查 Future 是否有效,即是否具有共享状态** 此函数的行为应与相应的 std::future 函数相同** @returns 如果 Future 可用则返回 true,否则返回 false*/bool valid() const noexcept;/*** @brief 等待值或错误变为可用** 此函数的行为应与相应的 std::future 函数相同*/void wait() const;/*** @brief 等待给定的时间段,或者直到值或错误变为可用** 此函数的行为应与相应的 std::future 函数相同** @param timeoutDuration 要等待的最大持续时间* @returns 表示是超时还是值可用的状态*/template <typename Rep, typename Period>future_status wait_for(const std::chrono::duration<Rep, Period>& timeoutDuration) const;/*** @brief 等待直到给定的时间,或者直到值或错误变为可用** 此函数的行为应与相应的 std::future 函数相同** @param deadline 要等待的最晚时间点* @returns 表示是否到达时间或值是否可用的状态*/template <typename Clock, typename Duration>future_status wait_until(const std::chrono::time_point<Clock, Duration> deadline) const;/*** @brief 注册一个可调用对象,当 Future 准备好时调用该对象** 当调用 @a func 时,保证 get()和 GetResult()不会阻塞** @a func 可以在此调用的上下文中调用,也可以在 Promise::set_value()或 Promise::SetError()或其他地方的上下文中调用** @a then 的返回类型取决于 @a func 的返回类型(也称为延续)** 设 U 为延续的返回类型(即与 std::result_of_t<std::decay_t<F>(Future<T,E>)>等效的类型)* - 如果 U 对于某些类型 T2、E2 是 Future<T2,E2>,那么 @a then()的返回类型是 Future<T2,E2>。这称为隐式 Future 展开* - 如果 U 对于某些类型 T2、E2 是 Result<T2,E2>,那么 @a then()的返回类型是 Future<T2,E2>。这称为隐式 Result 展开* - 否则它是 Future<U,E>** @param func 要注册的可调用对象* @returns 延续结果的新 Future 实例*/template <typename F>auto then(F&& func) -> Future<SEE_COMMENT_ABOVE>;/*** @brief 返回异步操作是否已完成** 如果此函数返回 true,则保证 get()、GetResult()和等待调用不会阻塞** 如果 valid()返回 false,则此函数的行为未定义** @returns 如果 Future 包含值或错误则返回 true,否则返回 false*/bool is_ready() const;
};

ara::core::GetResult ()ara::core::Future 对象中返回结果(Result)或者错误(Error),并且不会抛出异常。get () 返回相应的 ara::core::Future  并且 / 或者抛出异常。

有关自适应平台中错误处理方法的详细文档,请参阅 [Specification of Adaptive Platform Core.pdf] 中 “错误处理” 章节。

下面是使用 “基于异常” 的方法来同步调用一个方法的示例:

using namespace ara::com;int main() {// 一些获取句柄的代码//...RadarServiceProxy service(handle);// 通过服务的 Calibrate 方法(传入 myConfigString 参数)调用,得到一个包含 Calibrate::Output 类型的 Future 对象Future<Calibrate::Output> callFuture = service.Calibrate(myConfigString);/*** 现在我们进行一个阻塞式的 get()调用,当接收到结果(有效结果或者异常)时,该调用将会返回。** 如果 Calibrate 方法可能抛出异常并且服务端已经设置了异常,那么这个异常将会通过 get()抛出*/Calibrate::Output callOutput = callFuture.get();// 对得到的 callOutput 进行处理...return 0;
}

简而言之:从开发人员的角度来看,对服务方法的同步调用仅仅包含()操作符调用语法,以及随后对返回的 future (同步 / 异步结果)进行阻塞式的 get () 调用。除了从对 get () 的阻塞调用中恢复执行之外,一旦方法结果可用,用户还有其他方式从通信管理实现中获得通知:

  • wait” 的变体,ara::core::Future std::future 中继承了这些变体。它们主要提供了阻塞等待 future 完成的功能。

  • 通过 then()注册一个回调方法。这是对 std::future  的扩展之一;详见  [Specification of Adaptive Platform Core.pdf]

简单的无参数的 wait() 变体与 get () 具有相同的阻塞语义,即阻塞直到 future 有一个有效的结果(值或异常)。 “wait” 的变体,你要么给出一个持续时间( wait_for())要么给出一个目标时间点( wait_until()),如果  future 有一个有效的结果或者超时 / 最后期限限制已到,它们就会返回 —— 因此它们都返回 future_status 以区分这些情况。 获得  future 结果(有效或异常)通知的最后一种可能性是通过 then()注册一个回调方法。这是  ara::core::future std::future  的扩展之一。

如你所见,到目前为止我们讨论的(并且在示例中部分展示了)获取 future 方法结果的所有可能性 —— 阻塞式的 “get”、所有 “wait” 变体和 “then”—— 都是事件驱动的。也就是说,方法结果(或错误)的到达事件要么导致被阻塞的用户线程恢复执行,要么导致对用户提供的函数的调用!

当然,有些情况下,ara::com用户根本不希望他的应用程序(进程)被某些方法调用返回事件激活!想象一个典型的实时(RT)应用程序,它必须完全控制自己的执行。我们已经在事件数据访问的上下文中讨论了这个实时 / 轮询用例(小节 5.3.5.3)。对于方法调用,同样的方法也适用!

因此,我们预见到了与  ara::core::future 相关的以下使用模式:通过()操作符调用服务方法后,只需使用 ara::core::Future::is_ready () 进行轮询,以查看方法调用是否已经完成。此调用被定义为非阻塞的。当然,它可能涉及一些系统调用 / 上下文切换(例如查看一些内核缓冲区),这并不是无代价的,但它不会阻塞!在ara::core::Future::is_ready () 返回 true 之后,可以保证下一次对 ara::core::Future::get () 的调用不会阻塞,而是在没有错误的情况下立即返回有效的值,或者在出现错误的情况下抛出异常。

5.3.6.3 Canceling Method Result

在某些情况下,你可能已经通过()操作符调用了一个服务方法,该方法返回了一个  ara::core::future ,但你已经不再关心结果了。

甚至可能你已经通过 ara::core::Future::then() 为它注册了一个回调。与其放任不管并 “忽略” 这个回调,你应该明确地告知通信管理(Communication Management)。

这样可以释放资源,并避免在绑定实现层面产生不必要的处理负载。要告知你不再对方法调用结果感兴趣,只需让  ara::core::Future  超出作用域,这样它的析构函数(destructor)就会被调用。

调用  ara::core::Future  的析构函数是向绑定实现发出的一个信号,表示不应再调用为此  future 注册的任何回调,方法调用结果的预留 / 分配内存可以被释放,并且方法结果的事件等待机制应该停止。

显然,为了触发对析构函数的调用,你可以让  future 超出作用域。根据应用程序架构的不同,这可能并不可行,因为你可能已经将返回的  ara::core::Future  分配给了某个作用域更大的变量。

为了解决这个问题, ara::core::Future 是可默认构造的。因此,你可以像下面的示例所示,简单地用一个默认构造的实例覆盖变量中返回的  ara::core::Future 

using namespace ara::com;// 定义一个存储 Calibrate::Output 类型的 Future 对象
Future<Calibrate::Output> calibrateFuture;int main() {// 一些获取句柄的代码//...RadarServiceProxy service(handle);// 调用服务的 Calibrate 方法(传入 myConfigString 参数),并将返回的 Future 对象赋值给 calibrateFuturecalibrateFuture = service.Calibrate(myConfigString);/*** 发生了一些状态改变,使得 calibrate 方法的结果变得多余了...* * 我们通过将变量重置为一个新的默认构造的 Future 对象来强制删除(原来的 Future 对象)*/calibrateFuture = Future<Calibrate::Output>();// 继续执行其他操作...return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/54062.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[技术杂谈]暗影精灵8plus电竞版台式机安装和使用注意

最近买回二手台式机准备做深度学习训练模型使用。由于个人不是十分有钱&#xff0c;因此下血本入手一台&#xff0c;不然深度学习玩不转。配置&#xff1a;i9-12900K / 64G d4 3733频率 / 1TSSD2TB机械 / RTX3090 24G显卡 旗舰版 机箱45L超大机箱。买回来后整体不错&#…

Eclipse折叠if、else、try catch的{}

下载插件com.cb.eclipse.folding_1.0.6.jar。将插件放到eclipse的dropins文件夹中。修改配置&#xff0c;然后保存&#xff0c;重启Eclipse即可。

Vue3项目开发——新闻发布管理系统(七)

文章目录 九、新闻分类管理模块设计开发1、新闻分类主页面设计2、封装页面组件3、改造页面4、新闻分类表格渲染4.1封装API,获取新闻分类数据4.2 表格动态渲染4.3表格增加 loading 效果5、实现新闻分类添加和编辑功能5.1 点击显示弹层5.2封装弹层组件 CateEdit5.3 准备弹层表单…

openstack之cinder介绍

概念 cinder 为虚拟机提供管理块存储服务。支持的文件系统&#xff1a;lvm、iscsi、nfs、san、RBD 组件构成及功能介绍 cinder api&#xff1a;在控制节点运行&#xff0c;管理服务的接口&#xff0c;被命令行、其他组件调用&#xff1b; cinder scheduler&#xff1a;类似n…

Ruoyi Cloud K8s 部署

本文视频版本:https://www.bilibili.com/video/BV1xF4Se3Esv 参考 https://blog.csdn.net/Equent/article/details/137779505 https://blog.csdn.net/weixin_48711696/article/details/138117392 https://zhuanlan.zhihu.com/p/470647732 https://gitee.com/y_project/Ruo…

初学Linux(学习笔记)

初学Linux&#xff08;学习笔记&#xff09; 前言 本文跳过了Linux前期的环境准备&#xff0c;直接从知识点和指令开始。 知识点&#xff1a; 1.目录文件夹&#xff08;Windows&#xff09; 2.文件内容属性 3.在Windows当中区分文件类型是通过后缀&#xff0c;而Linux是通过…

AtCoder ABC370 A-D题解

比赛链接:ABC370 AT 上 400 分寄。 Problem A: Code #include <bits/stdc.h> using namespace std; int main(){int L,R;cin>>L>>R;if(LR)cout<<"Invalid"<<endl;else if(L1)cout<<"YES"<<endl;elsecout<…

SAP到底是谁的系统?business or IT?

作为SAP顾问&#xff0c;我们可能常常听到业务部门的用户说“SAP是你们的系统&#xff0c;你们要把这些问题搞定”。那么到底这个SAP系统是SAP顾问所在的IT部门的吗&#xff1f;这其实是一个很好的问题&#xff0c;反映出企业对于与SAP系统相关问题的职责划分。每个企业的情况还…

嵌入式硬件基础知识

嵌入式硬件基础知识涵盖了嵌入式系统中的硬件组成及其工作原理&#xff0c;涉及处理器、存储器、外设接口、电源管理等多个方面。这些硬件共同构成了一个完整的嵌入式系统&#xff0c;用于执行特定任务。下面我们来详细介绍嵌入式硬件的基础知识。 1. 嵌入式系统的组成 嵌入式…

面试常见题之spring

在Java软件工程师面试中&#xff0c;关于Spring的题目是非常常见的。本文准备了20个Spring相关的面试题目及其参考答案&#xff0c;这些题目涵盖了Spring框架的基本概念、核心功能、设计模式、IoC容器、AOP、事务管理等多个方面&#xff0c;旨在全面考察面试者对Spring框架的掌…

LeetCode_sql_day26(184,1549,1532,1831)

描述 184.部门工资最高的员工 表&#xff1a; Employee ----------------------- | 列名 | 类型 | ----------------------- | id | int | | name | varchar | | salary | int | | departmentId | int | -----------------…

list从0到1的突破

目录 前言 1.list的介绍 2.list的常见接口 2.1 构造函数&#xff08; (constructor)&#xff09; 接口说明 2.2 list iterator 的使用 2.3 list capacity 2.4 list element access 2.5 list modifiers 3.list的迭代器失效 附整套练习源码 结束语 前言 前面我们学习…

FastAdmin CMS 操作手册

FastAdmin CMS 操作手册 概述&#xff1a; 安装&#xff1a; 配置&#xff1a; 模板&#xff1a; 模板目录&#xff1a; 标签&#xff1a; 全局&#xff1a; 文章&#xff1a; 专题&#xff1a; 栏目&#xff1a; 公共参数&#xff1a; 单页&#xff1a; 特殊标签&#xff1a;…

138_Java基础_常用类搭建教程java部署mysql5.5

安装&#xff1a; yum -y install build-essential QQ1594457675 安装&#xff1a;更多依赖包 yum -y install gcc automake autoconf libtool make 安装&#xff1a;数据库 这里需要注意数据库密码记得修改 数据库账号QQ 数据库密码1594457675 yum -y install gcc …

Linux 文件 IO 管理(第一讲)

Linux 文件 IO 管理&#xff08;第一讲&#xff09; 回顾 C 语言文件操作&#xff0c;提炼理解新创建的文件为什么被放在可执行文件的同级目录下&#xff1f;上述 log.txt 何时被创建&#xff1f;又是谁在打开它&#xff1f;那文件没有被打开的时候在哪里&#xff1f;一个进程可…

电脑的固态硬盘

常见种类 1.SATA接口&#xff1a;一般由一个铁盒子&#xff0c;里面装着控制芯片&#xff0c;以及内存颗粒组成的SSD硬盘。 比机械硬盘读写速度快&#xff0c;比M.2读写速度慢。目前常用的是3.0 2.M.2 PCI-E接口&#xff1a;无机械零件设计&#xff0c;相当于没有噪音。速度比…

Chrome谷歌浏览器登录账号next无反应

文章目录 问题描述 我们的Chrome浏览器在更新之后&#xff0c;会出现登录谷歌账号的时候&#xff0c;当你输入你的谷歌邮箱之后&#xff0c;点击 n e x t next next,也就是下一步的时候&#xff0c;页面没有反应&#xff0c;也就是没有跳转到输入密码的页面。 分析 根据logs里…

#ifndef PROJ_EXTEND_KALMAN_HPP_#define PROJ_EXTEND_KALMAN_HPP_ c++ 语句解释

#ifndef, #define, 和 #endif 是 C 中用于防止头文件被多次包含的预处理指令。它们共同构成了一个叫做 include guards 的机制。下面是这些指令的详细解释&#xff1a; 1. #ifndef&#xff08;如果没有定义&#xff09; #ifndef 是 #if&#xff08;如果&#xff09;指令的变体…

借助大模型将文档转换为视频

利用传统手段将文档内容转换为视频&#xff0c;比如根据文档内容录制一个视频&#xff0c;不仅需要投入大量的时间和精力&#xff0c;而且往往需要具备专业的视频编辑技能。使用大模型技术可以更加有效且智能化地解决上述问题。本实践方案旨在依托大语言模型&#xff08;Large …

3D GS 测试自己的数据

环境配置 win11 vs2019cuda11.8driver522.06python3.10pytorch 2.4.0colmap3.8&#xff08;可选&#xff0c;用于将图像生成点云&#xff09; 安装 1 minicodagit 略 2 vs2019 在装cuda前安装&#xff0c; 选择c桌面开发即可&#xff0c; 环境变量path中配置C:\Program…