文章目录
- 1. 概述
- 2. 支持一个发布者多个订阅者
- 2.2 Iceoryx为何不支持多个发布者发布到同一个主题
- 3. Iceoryx的架构和数据传输示意图
- 3.1 发布者与订阅者的通信机制
- 3.2 零拷贝共享内存通信机制
- 4. 使用事件驱动机制
- 4.1 WaitSet机制
- 4.2 Listener机制
- 5. 已知限制
- 6. 参考
1. 概述
本文将通过图示简要介绍高性能通信中间件Iceoryx的核心特点。详细介绍请参见:C++高性能通信:了解Iceoryx与零拷贝技术的实现与应用。
2. 支持一个发布者多个订阅者
Iceoryx支持一个发布者对应多个订阅者,每个发布者将数据发布到特定的主题,多个订阅者可以订阅该主题并接收数据。
2.2 Iceoryx为何不支持多个发布者发布到同一个主题
Iceoryx不支持多个发布者发布到同一个主题,主要原因如下:
- 数据一致性:多个发布者需要额外机制确保数据一致性和顺序性,增加系统复杂性和延迟。
- 内存管理:多个发布者同时访问同一共享内存区域,带来内存管理挑战。
- 数据竞态:多个发布者可能导致数据竞态问题,需要额外锁机制解决,降低系统性能。
这种设计选择保持了系统的简单性和高效性,避免了多发布者带来的复杂性,同时充分利用共享内存机制,实现高性能数据传输。
3. Iceoryx的架构和数据传输示意图
下图展示了Iceoryx的架构与数据传输流程,主要包括发布者(Publisher)、订阅者(Subscriber)、RouDi守护进程(Daemon)和共享内存。
- 写入数据块(Write Chunk):发布者将数据写入共享内存中的数据块(Chunk)。
- 发布信号量(Post Semaphore):发布者写入数据后,通过信号量(Semaphore)通知RouDi守护进程有新数据可用。
- 通知(Notification):RouDi守护进程收到信号量通知后,通过消息队列(Message Queue)将新数据的通知发送给所有订阅者。
- 读取数据块(Read Chunk):订阅者接收到RouDi的通知后,从共享内存中读取数据块。
RouDi守护进程负责管理发布者和订阅者的配置和注册,通过消息队列实现通知机制,确保发布者和订阅者之间的高效通信。共享内存用于存储和传输数据,极大地避免了数据拷贝。
3.1 发布者与订阅者的通信机制
在Iceoryx中,发布者和订阅者通过消息队列与RouDi(Runtime and Discovery Daemon)进行通信和配置。
- 注册:发布者和订阅者启动时向RouDi注册,声明自己发布或订阅的主题。
- 连接:RouDi根据注册信息建立发布者和订阅者之间的连接,并配置共享内存区域。
- 通信:发布者将数据写入共享内存,通过消息队列通知RouDi;订阅者接收RouDi的通知,从共享内存读取数据。
3.2 零拷贝共享内存通信机制
- 零拷贝方法:Iceoryx使用基于共享内存的零拷贝方法,允许发布者和订阅者通过共享内存实现高效通信,避免数据拷贝。
- 共享内存映射:共享内存是一种物理内存,通过映射到进程的虚拟地址空间,使多个进程能够访问同一内存区域。
- 进程间共享:共享内存段可以被多个进程映射,不同进程中的映射地址可能不同。这些共享内存段位于RAM或文件系统中,通过映射到进程的虚拟地址空间,使其可访问。
4. 使用事件驱动机制
4.1 WaitSet机制
WaitSet用于通过非忙等待将线程置于睡眠状态,并等待用户定义的事件发生。通常,这些事件对应于特定订阅者或客户端的数据可用性。
- 创建WaitSet:创建一个WaitSet,附加多个订阅者和/或客户端和用户触发器,然后等待一个或多个附加对象发出事件。
- 接收通知:当事件发生时,接收到一个名为
notificationVector
的所有发生事件的列表。 - 处理数据:在订阅者或客户端通知WaitSet有新数据或新响应可用时,直接从订阅者或客户端收集数据。
WaitSet使用反应器模式,通过推送策略通知用户发生的事件。更多信息请参见WaitSet示例。
4.2 Listener机制
Listener用于将自定义回调连接到用户定义的事件。与WaitSet不同,它通过在后台线程中执行连接的自定义回调来响应这些事件。
- 线程安全:Listener是完全线程安全的,但大多数可以附加到Listener的对象不是线程安全的。要么对象完全由Listener处理,要么用户必须通过其他手段确保线程安全。
- 用例:创建一个Listener并附加多个订阅者。当有新数据可用时,将执行相应的连接回调,例如打印到控制台或执行计算算法。另一种用例是将服务器附加到Listener,每当接收到请求时,执行创建并发送响应的连接回调。
与WaitSet一样,Listener使用反应器模式。更多信息请参见回调示例。
5. 已知限制
- RouDi Daemon故障:RouDi Daemon不能崩溃,否则会导致系统故障。RouDi守护进程必须在任何应用程序之前运行。
- 固定虚拟地址依赖:目前,需要为所有进程mmap特定的基址。
- 内存池配置:编译后内存池无法配置,仅支持静态配置。
- 单个发布者限制:仅支持单个发布者,不支持多个。
6. 参考
待补充