AUTOSAR_EXP_ARAComAPI的5章笔记(5)
☞ 返回总目录
5.3.5.3 Accessing Event Data — aka Samples
成功订阅了一个事件后,服务消费者如何接收Sample呢?在典型的进程间通信(IPC)实现中,从服务提供者发送到订阅的Proxy实例的Sample会在缓冲区中积累/排队(例如内核缓冲区、特定的 IPC 实现控制的共享内存区域等)。因此,必须采取明确的行动,从这些缓冲区中获取那些 Sample,对其进行反序列化,然后以正确的Sample类型的形式将它们放入事件包装类实例特定的缓存中。触发此操作的 API 是GetNewSamples()
/**
* \brief Get new data from the Communication Management
* buffers and provide it in callbacks to the given callable f.
*
* ....
*/
template <typename F>
ara::core::Result<size_t> GetNewSamples(F&& f,
size_t maxNumberOfSamples = std::numeric_limits<size_t>::max());
GetNewSamples()是一个模板函数,第一个参数f非常灵活,是由用户提供的回调函数,它必须满足特定的签名:
void(ara::com::SamplePtr<SampleType const>)
第二个参数是size_t类型,用于控制从CM中间件缓冲区中获取并反序列化后呈现给应用程序的 Sample的最大数量。
在调用GetNewSamples() 时,ara::com实现首先检查应用程序持有的Sample数量是否已经超过了之前调用Subscribe() 订阅时承诺的最大数量。如果超过了,则返回一个ara::Core::ErrorCode。另一方面,ara::com实现检查底层缓冲区是否包含新的Sample。如果有新的Sample,就将其反序列化为一个样本槽,并指向回调函数f 。这个处理过程(检查缓冲区中是否有更多Sample并回调用户提供的回调函数f)会重复进行,直到以下任意情景发生:
-
缓冲区中没有新的Sample
-
缓冲区中虽然有很多Sample,但在调用GetNewSamples()时用户提供的maxNumberOfSamples参数已经达到。
-
缓冲区中虽然有很多Sample,但应用程序已经超过了在Subscribe()中承诺的maxSampleCount。
在回调函数f实现中,可以决定如何使用传递的Sample 参数(例如:通过最终深入检查事件数据):
- 因为对新Sample不感兴趣而 “丢弃” 它,
- 还是保留Sample以备后用。
为了理解保留/丢弃Sample的含义,必须完全理解作为Sample数据访问 / 入口点的SamplePtr 的语义(下一章将对此进行说明)。返回的ara::core::Result包含要么是一个错误码,要么(在成功的情况下)是在GetNewSamples()调用上下文中对回调函数f的调用次数。
5.3.5.4 Event Sample Management via SamplePtrs
从ara::com实现传递到应用程序层的SamplePtr,从语义角度来看,是一个独占指针(类似于std::unique_ptr),当ara::com实现传递它时,会发生所有权转移。
从现在起,应用程序负责底层样本的生命周期管理。只要用户不销毁SamplePtr 或在SamplePtr 实例上显式地调用赋值操作 / 修改器来释放Sample,ara::com实现就不能回收这个Sample占用的内存槽。
那些存储事件样本数据的内存槽是由ara::com实现分配的。内存槽的分配通常发生在调用Subscribe()的上下文中,应用程序通过参数maxSampleCount (最大采样计数)定义同时可访问的最大事件数据样本数量。在后续的GetNewSamples()调用中,ara::com实现会填充这样一个 “样本槽”(如果有空闲的),并在应用程序的回调函数f中传递一个指向它的SamplePtr 。
在实现回调函数f时,应用程序设计者决定如何使用这个传入的SamplePtr 。如果设计者想保留样本以供后续访问(即在回调返回后),设计者会在其应用程序合适的外部作用域进行SamplePtr复制。是否复制它可能仅仅取决于事件Sample数据的属性 / 值,在这种情况下,回调函数基本上是对接收的事件SamplePtr*的个 “过滤器”。
由于我们说过SamplePtr的行为类似于std::unique_ptr,所以需要稍微修正一下上述说法:当决定保留那个事件样本时,实现显然不是复制传入的SamplePtr,而是将其移动到外部作用域位置。
在5.5 的小例子中在handleBrakeEventReception()方法中,忽略其他内容,仅就回调函数的实现而言,它实现了简单的SamplePtr过滤,并将其移动到具有 “最近 N 个” 语义的全局存储中以供以后使用 / 处理。