【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
和mcu固件、上位机软件不太一样的地方,嵌入式设备上面上面的工业软件一般都是多进程的形式。相比较多线程而言,整个系统就不会因为一个线程的bug造成崩溃,这也是大多数工业、军工和医疗系统采用多进程的原因。此外,工业嵌入式软件一般由不同的部门、不同的人员开发,彼此之间用多进程开发,也方便升级、调试和管理。只要大家都按照一定的形式和接口去开发和编程就可以了,相互之间没有约束。
1、多进程通信的思路
既然是多进程开发,那么会势必涉及到通信的问题。默认情况我们一般是这么做的,所有的进程当中,有一个核心程序,它最重要的工作是负责不同进程之间的消息传递。这样的话,每一个进程自己有哪些消息要发布,有哪些消息要订阅,这些都是一清二楚的。对于核心程序来说,它的工作就是把那些发布的消息,转到订阅的进程上面。因此,这个核心程序的稳定性要求就特别高。
下面就举例说明一种基于共享内存的通信方式,用boost实现,直接输入g++ shared.cpp -g -o shared && ./shared即可。
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>
using namespace boost::interprocess;
int main()
{
try {
// 创建共享内存对象,如果不存在则创建,如果存在则打开
shared_memory_object shm_obj(open_or_create, "MySharedMemory", read_write);
// 设置共享内存大小为1000字节
shm_obj.truncate(1000);
// 映射共享内存到当前进程的地址空间
mapped_region region(shm_obj, read_write);
// 获取共享内存的起始地址
void* addr = region.get_address();
// 在共享内存中写入数据
std::strcpy(static_cast<char*>(addr), "Hello, shared memory!");
// 从共享内存中读取数据
std::cout << "Message read from shared memory: " << static_cast<const char*>(addr) << std::endl;
// 删除共享内存对象
shared_memory_object::remove("MySharedMemory");
}
catch (std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
return 0;
}
2、同步和异步
既然是通信,那么就涉及到同步和异步的请求。这里,我们就先说一下异步请求。所谓的异步请求,就是subscribe和publish之间都是异步展开的。什么时候publish出去、什么时候subscribe拿到数据,这些都是分开来的。而同步请求,一般一个进程主要给另外一个进程发起请求,这个时候不拿到结果,发送请求的进程是不会退出的,会一直阻塞在那里。
当然,鉴于核心程序稳定性的考虑,同步通信中的阻塞和唤醒的操作最好做成sdk,在各个程序侧来完成,这样是比较合理的。
3、调试和调优
多进程通信的开发模式还有一个好处,那就是调试和调优。一个软件如果涉及了太多的模块,那么开发稳定性肯定是会受到影响的,并且调试、调优也不方便的。但是一旦分开来了,大家关心的就是自己的数据什么时候拿到、什么时候送出去,程序崩溃了也是自己的事情,责任上面划分得很清楚。
至于说调优,那也变得简单了。我们开发一个功能,从拿到数据到送出结果,每一个步骤都可以加上时间戳,这样有了这个事件戳,哪部分花费的时间最长,基本上也就一目了然了。
4、通信方式的实现
不同进程之间的通信实现方式有很多,比如说pipe、共享内存、网络等等。个人其实是比较推荐网络的实现方式。之前,我们编写网络通信的时候,其实主要是为了实现不同pc、server之间的通信。但是如果ip设置成127.0.0.1,这个时候其实是可以实现一台pc上不同process之间进行通信的。实现也比较方便。虽然中间可能会涉及到数据的copy和处理,但是整体上还是比较可控的。如果对于数据转发有很高的性能要求,这个时候就只能进行指针的传递了。
5、关于多进程通信的另外一个选择ros
ros,全称robot operating system。本身它其实不是一个操作系统,只是一个框架。只不过这个框架上面有很多的算法、很多的工具、还有一些别人搭建好的开发平台,个人不需要从0到1开始开发。所以用ros实现不同进程之间的通信也是很好的一个选择。要说缺点的话,就是ros安装稍微麻烦了一点,占用空间稍微多了一点。当然,现在的ros已经变成了一个生态,很多的开发板,比如说像树莓派4b这样的开发板就支持ros的开发和运行。这样的话,开发者可以专心地把重点放到驱动、业务和算法的开发上面了。
有兴趣的同学,可以先在自己的pc电脑上安装一个ubuntu虚拟机,看看ubuntu上面是如何安装和使用ros系统的。
https://feixiaoxing.blog.csdn.net/article/details/132789849
6、多进程通信的开发输出
因此,通过以上的分析,我们也知道一个多进程开发的系统,至少应该有一个core调度程序,还有一个sdk。sdk里面有消息的注册、回调、服务的注册、回调这四个基本功能。