软件定制开发供应商Iceoryx整体

记录iceoryx学习过程,欢迎交流

一、架构

1. RouDi

RouDi 软件定制开发供应商管理共享内存并负责服务发现,软件定制开发供应商使订阅者能够找到发布软件定制开发供应商者提供的主题。

软件定制开发供应商介绍中有一句话:“软件定制开发供应商当应用程序崩溃时,RouDi 软件定制开发供应商会清理所有资源。软件定制开发供应商由于我们大多是无锁的进程间机制(只有最后一个锁;我们正在努力移除它),与使用锁定的传统机制相比,基于 iceoryx 的通信更加可靠。” 这个可以再看一下,我们平常遇到的锁的问题,iceoryx是怎么处理的?


2. 整体架构

 

  1. iceoryx hoofs:Handy Objects Optimized For Safety (hoofs) 是一个库,包含各种构建块,例如固定大小的容器、并发类和来自即将发布的 C++ 标准版本的现代下一代 C++ 构造。
  2. iceoryx posh:该包iceoryx_posh(POSIX Shared memory)包含与共享内存进程间通信相关的所有内容。
  3. Core library:本节描述核心库的命名空间。
  4. popo: 命名空间posh端口包含用于传输数据的用户 API 类。
  5. capro:命名空间规范协议实现了规范协议模式 协议,用于iceoryx_posh连接和popo::Publisher发现popo::Server。
  6. mepoo:命名空间内存池包含所有与内存相关的类。例如MemoryManager或SharedPointer。
  7. version:命名空间版本包含 ABI 兼容性检查。
  8. build:命名空间构建包含某些可以在编译前更改的最大值。
  9. Gatway library:网关库及其命名空间gw包含用于创建网关的通用抽象。它们被iceoryx_dds.
  10. RouDi library:库 RouDi 及其命名空间roudi包含 RouDi 中间件守护程序使用的类。
  11. iceoryx C binding:该模块iceoryx_binding_c使 C 中的进程间通信功能iceoryx_posh可用。
  12. iceoryx DDS:该软件包提供了一个使用Eclipse Cyclone DDSiceoryx_dds的双向 DDS 网关。网关可用于通过网络发送数据,例如通过以太网。
  13. iceoryx introspection:自省客户端可用于实时调试并提供当前系统的信息,如内存使用情况和已建立的连接。

二、真正的零拷贝

1. 典型IPC中间件

典型IPC中间件解决方案:

2. 零拷贝方案

3. 细节

 Iceoryx 的一个重要方面是发布者可以在订阅者仍在阅读时再次写入,因为没有订阅者的干扰。如果前一个内存块仍在使用中,则只需为发布者分配一个新的内存块。(需要看代码理解清楚这一句话)

由于消息有效负载未序列化,因此消息对于发布者和订阅者必须具有相同的内存布局。对于特定处理器上的 IPC,这可以通过使用具有相同设置的相同编译器来确保。(iceoryx 的共享内存回收是怎么做的? )

 

三、接口封装

创建发布者:

  1. //创建一个具有唯一名称的进程,使其与RouDi通信
  2. iox::runtime::PoshRuntime::initRuntime("some_unique_name");
  3. struct CounterTopic
  4. {
  5. uint32_t counter;
  6. };
  7. //创建发布者,括号中
  8. iox::popo::Publisher<CounterTopic> publisher({"Group", "Instance", "CounterTopic"});
  9. //使用发布者发送数据
  10. auto result = publisher.loan();
  11. if(!result.has_error())
  12. {
  13. auto& sample = result.value();
  14. sample->counter = 30;
  15. sample.publish();
  16. }
  17. else
  18. {
  19. // handle the error
  20. }

创建订阅者:
问题:这是每一个订阅者一个线程吗?

  1. iox::popo::Subscriber<CounterTopic> subscriber({"Group", "Instance", "CounterTopic"});
  2. while (keepRunning)
  3. {
  4. // wait for new data (either sleep and wake up periodically or by notification from the waitset)
  5. auto result = subscriber.take();
  6. if(!result.has_error())
  7. {
  8. auto& sample = result.value();
  9. uint32_t counter = sample->counter;
  10. //process the data
  11. }
  12. else
  13. {
  14. //handle the error
  15. }
  16. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  17. }


四、消息传输

数据被唤醒的方式:定期检查, WaitSet 和 Listener 显示等待数据;

1. WaitSet

WaitSet 可用于放弃控制(使线程进入睡眠状态)并等待用户定义的事件发生。通常,这些事件对应于特定订阅者的数据可用性。这样我们可以在数据可用时立即唤醒,并在没有数据可用时避免不必要的唤醒。

一个典型的用例是创建一个 WaitSet,附加多个订阅者和用户触发器,然后等待一个或多个附加对象发出事件信号。如果发生这种情况,则会收到所有已发生事件的列表。这样就可以在订阅者向 WaitSet 发出新数据可用的信号时直接从订阅者那里收集数据。

WaitSet 使用,并通过推送策略通知用户发生了一个附加事件。

  1. #include "iceoryx_hoofs/cxx/optional.hpp"
  2. #include "iceoryx_hoofs/posix_wrapper/signal_handler.hpp"
  3. #include "iceoryx_posh/popo/subscriber.hpp"
  4. #include "iceoryx_posh/popo/user_trigger.hpp"
  5. #include "iceoryx_posh/popo/wait_set.hpp"
  6. #include "iceoryx_posh/runtime/posh_runtime.hpp"
  7. #include "topic_data.hpp"
  8. #include <atomic>
  9. #include <iostream>
  10. //! [sig handler]
  11. std::atomic_bool keepRunning{true};
  12. iox::cxx::optional<iox::popo::WaitSet<>> waitset;
  13. static void sigHandler(int sig IOX_MAYBE_UNUSED)
  14. {
  15. keepRunning = false;
  16. if (waitset)
  17. {
  18. waitset->markForDestruction();
  19. }
  20. }
  21. //! [sig handler]
  22. int main()
  23. {
  24. // initialize runtime
  25. iox::runtime::PoshRuntime::initRuntime("iox-cpp-waitset-basic");
  26. // create waitset inside of the optional
  27. //! [create waitset]
  28. waitset.emplace();
  29. // register signal handler to handle termination of the loop
  30. auto signalGuard = iox::posix::registerSignalHandler(iox::posix::Signal::INT, sigHandler);
  31. auto signalTermGuard = iox::posix::registerSignalHandler(iox::posix::Signal::TERM, sigHandler);
  32. // create subscriber
  33. iox::popo::Subscriber<CounterTopic> subscriber({"Radar", "FrontLeft", "Counter"});
  34. // attach subscriber to waitset
  35. waitset->attachState(subscriber, iox::popo::SubscriberState::HAS_DATA).or_else([](auto) {
  36. std::cerr << "failed to attach subscriber" << std::endl;
  37. std::exit(EXIT_FAILURE);
  38. });
  39. //! [create waitset]
  40. //! [mainloop]
  41. while (keepRunning)
  42. {
  43. // We block and wait for samples to arrive.
  44. auto notificationVector = waitset->wait();
  45. for (auto& notification : notificationVector)
  46. {
  47. // We woke up and hence there must be at least one sample. When the sigHandler has called
  48. // markForDestruction the notificationVector is empty otherwise we know which subscriber received samples
  49. // since we only attached one.
  50. // Best practice is to always acquire the notificationVector and iterate over all elements and then react
  51. // accordingly. When this is not done and more elements are attached to the WaitSet it can cause
  52. // problems since we either miss events or handle events for objects which never occurred.
  53. if (notification->doesOriginateFrom(&subscriber))
  54. {
  55. // Consume a sample
  56. subscriber.take()
  57. .and_then([](auto& sample) { std::cout << " got value: " << sample->counter << std::endl; })
  58. .or_else([](auto& reason) {
  59. std::cout << "got no data, return code: " << static_cast<uint64_t>(reason) << std::endl;
  60. });
  61. // We could consume all samples but do not need to.
  62. // If there is more than one sample we will wake up again since the state of the subscriber is still
  63. // iox::popo::SubscriberState::HAS_DATA in this case.
  64. }
  65. }
  66. }
  67. //! [mainloop]
  68. std::cout << "shutting down" << std::endl;
  69. waitset.reset();
  70. return (EXIT_SUCCESS);
  71. }

 2. Listener

Listener 是实现推送方法以检测和响应某些事件的构建块之一。与 WaitSet 的两个主要区别是 Listener 是事件驱动的,而不是 WaitSet 的事件和状态驱动的,并且 Listener 创建了一个单独的后台线程,在该线程中执行事件回调,这与 WaitSet 的不同之处在于用户必须显式调用事件回调。

 

五、 共享内存管理模型

iceoryx 系统使用一个“管理”段来进行管理,并使用任意数量的“用户”段来进行服务之间的事件通信。

这些段在逻辑上被划分为“内存池”。内存池包含许多大小相等的“内存块”。

内存块是 iceoryx 系统中用于共享内存访问的基本单元。

六、限制

  1. a.由于 RouDi 守护进程导致的单点故障
  2. b.Roudi 守护进程需要比其他进程先启动
  3. c.固定虚拟地址依赖
  4. d.编译后不可配置的内存池
  5. e.不支持请求/响应过程调用
  6. f.只支持单发布
  7. g.不支持锁存数据传输

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发