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

AUTOSAR_EXP_ARAComAPI的5章笔记(11)

5.4.5 轮询和事件驱动处理模式

接下来,我们探讨服务提供方同时支持事件驱动和轮询行为的情况。从服务实例(此处指骨架子类实例)的角度来看,服务消费者的请求(包括服务方法或字段的 getter/setter 调用)可能在任意时间点到来。

在纯事件驱动的设置中,通信管理会生成相应的调用事件,并将这些事件转换为对服务实现提供的服务方法的具体方法调用。

这种设置的后果显而易见:

  • 对服务方法调用的响应通常会很快,因为延迟仅受一般机器负载和内在 IPC 机制延迟的限制。
  • 包含服务实例的操作系统进程的上下文切换率可能会很高且不确定,从而降低整体吞吐量。

正如您所见,服务提供方的事件驱动处理模式既有优点,也有缺点。然而,我们确实通过 ara::com 支持这种处理模式。我们支持的另一种极端情况是纯轮询风格的方法。在这里,服务提供方的应用程序开发人员明确调用 ara::com 提供的 API 来明确处理一个调用事件。

通过这种方式,我们再次支持典型的 RT(实时操作系统)应用程序开发人员。他们的应用程序通常由于低抖动周期性警报而被激活。当应用程序处于活动状态时,它以非阻塞方式检查事件队列,并明确决定愿意处理自上次激活时间以来积累的哪些事件。再次强调:应用程序进程的上下文切换 / 激活仅由特定的(RT)定时器接受,异步通信事件不应导致应用程序进程激活。

那么,ara::com 如何允许应用程序开发人员区分这些处理模式呢?骨架实例的行为由其构造函数的第二个参数控制,该参数的类型为 ara::com::MethodCallProcessingMode

/**
 * 服务实现方(骨架)的请求处理模式。
 * 
 * \note 平台供应商应完全按照此方式提供。
 */
enum class MethodCallProcessingMode { kPoll, kEvent, kEventSingleThread };

这意味着处理模式是为整个服务实例设置的(即其所有提供的方法都将受到影响),并且在骨架实例的整个生命周期内保持固定。构造函数中的默认值设置为 kEvent,下面将对此进行解释。

5.4.5.1 轮询模式

如果将其设置为 kPollara::com 实现将不会异步调用任何提供的服务方法!如果您想要处理下一个(假设后台有一个队列,用于存储传入的服务方法调用)挂起的服务调用,则必须在服务实例上调用以下方法:

/**
 * 从通信管理中获取下一个调用并执行它。
 * 
 * 仅在轮询模式下可用。
 */
ara::core::Future<bool> ProcessNextMethodCall();

我们使用 ara::core::Future 的机制来返回一个在未来完成的结果。这个返回的 ara::core::Future 有什么作用呢?它允许您在 “下一个请求” 被处理时得到通知。这有助于将服务方法调用一个接一个地连接起来,可能会非常有帮助。一个典型的 RT 应用程序的简单用例可能是:

  • RT 应用程序被调度。
  • 它调用 ProcessNextMethodCall 并使用 ara::core::Future::then() 注册一个回调。
  • 在与未完成请求相对应的中间件调用的服务方法完成后,回调被调用。
  • 在回调中,RT 应用程序决定是否有足够的时间来处理后续的服务方法。如果是这样,它会调用另一个 ProcessNextMethodCall

当然,这个简单的例子假设 RT 应用程序知道其服务方法的最坏情况运行时间(及其总体时间片),但这并非不可能!如果队列中确实存在未完成的请求并且已被分派,则通信管理会将返回的 ara::core::Future 的 bool 值设置为 true,否则将其设置为 false

这对于应用程序开发人员来说是一个比较舒适的指示器,即使请求队列为空,也不会重复调用 ProcessNextMethodCall。因此,在前一个调用返回的 ara::core::Future 的结果设置为 false 后直接调用 ProcessNextMethodCall 很可能不会执行任何操作(除非在这个最小的时间框架内偶然有一个新的请求进来)。

请注意,对于基于典型操作系统的 AP 产品,轮询模式会产生影响。除了排除由通信管理事件(传入的服务方法调用)导致的进程(包含服务实现)的上下文切换外,队列的位置也存在限制,它必须收集服务方法调用请求,直到轮询服务实现消耗它们为止。

队列必须在服务提供应用程序的地址空间之外实现,或者必须位于共享内存之类的位置,以便发送方能够直接写入队列。与共享内存解决方案相比,轮询服务提供程序对下面队列位置的访问可能会带来更高的成本 / 延迟。将队列放置在服务提供程序地址空间之外的典型解决方案是:

  • 内核空间:如果绑定实现使用套接字或管道机制,则写入调用的目标内核缓冲区类似于队列。在典型的操作系统中,调整 / 配置这些缓冲区的最大大小可能意味着需要重新编译内核。
  • 不同绑定 / 通信管理守护应用程序的用户地址空间:在用户空间内分配的队列的缓冲区空间分配通常可以更动态 / 灵活地完成。
5.4.5.2 事件驱动模式

如果将处理模式设置为 kEvent 或 kEventSingleThread,当服务消费者的服务调用到来时,ara::com 实现将异步将事件分派给服务方法实现。

与 kPoll 模式相反,在这里服务消费者隐式地控制 / 触发服务提供程序进程的激活及其方法调用!

那么 kEvent 和 kEventSingleThread 之间的区别是什么呢?kEvent 意味着 ara::com 实现可以同时调用服务方法实现。

这意味着对于我们的示例:如果 —— 在同一时间点 —— 来自不同服务消费者的一个对方法 Calibrate 的调用和两个对方法 Adjust 的调用到达,ara::com 实现允许从其内部线程池中获取三个线程,并同时为这两个服务方法执行这三个调用。

相反,kEventSingleThread 模式确保在服务实例上,ara::com 实现每次只调用一个服务方法。

这意味着 ara::com 实现必须为同一服务实例的传入服务方法调用事件排队,并一个接一个地分派它们。

为什么我们提供这两个变体呢?从功能的角度来看,只有 kEvent 就足够了!对于某些由于共享数据 / 一致性需求而无法同时运行的服务方法的服务实现,它可以简单地自己进行同步(例如通过 std::mutex)!

原因是 “效率”。如果您有一个服务实例实现,它具有广泛的同步需求,即无论如何几乎会同步所有服务方法调用,那么如果通信管理从其线程池资源中 “花费”N 个线程,而这些线程在直接获得硬同步后,将 N - 1 个线程发送到睡眠状态,这将是一种完全的资源浪费。


http://www.kler.cn/news/317644.html

相关文章:

  • ubuntu中Python解释器位置
  • C++性能分析easy_profiler
  • IntelliJ IDEA 2024.1.4 (Ultimate Edition)找不到Add Framework Support解决方法
  • Python爬虫之requests模块(一)
  • 全栈开发(三):springBoot3中使用mybatis-plus
  • 二分查找算法(4) _搜索插入位置
  • maxwell 输出消息到 redis
  • 【计算机基础】用bat命令将Unity导出PC包转成单个exe可执行文件
  • SQL面试常见题目
  • [uni-app]小兔鲜-01项目起步
  • Spring Boot 学习之路 -- 配置项目
  • C# 中yield 的使用详解
  • 【Python】多个dataframe存入excel的不同的sheet表里,而不会被覆盖的方法
  • 【ansible】role流程实验
  • 块匹配算法简介(上)
  • 腾讯云负载均衡ssl漏洞(CVE-201602183)解决
  • seL4 Capabilities(翻自官网)(一)
  • 【系统架构设计师】专业英语90题(附答案详解)
  • 代码随想录算法训练营第40天 动态规划part07| 题目: 198.打家劫舍 、 213.打家劫舍II 、 337.打家劫舍III
  • 软件设计-开闭原则
  • 2024年主动降噪头戴式耳机该如何选择?四款品牌高性价比推荐
  • 【TabBar嵌套Navigation案例-JSON的简单使用 Objective-C语言】
  • 用智能码二维码zhinengma.cn做产品说明书
  • 联通云 - 国产化全栈解决方案
  • 速通汇编(六)认识栈,SS、SP寄存器,push和pop指令的作用
  • LAMP架构搭建
  • 微服务远程调用(nacos及OpenFeign简单使用)
  • 程序员下班以后做什么副业合适?_35技术人员副业
  • VMware vCenter Server 8.0U3b 发布下载,新增功能概览
  • 微服务--Gateway网关