4. 核间通信基础

在多核实时系统中,核间通信(Inter-Processor Communication,IPC)是决定系统实时性、吞吐量和确定性的关键因素。VxWorks 为多核环境提供了多种 IPC 机制,包括共享内存、消息队列、管道和信号量。理解这些机制的底层原理、适用边界和性能特征,是进行多核实时应用设计的基础。

共享内存:最高带宽的核间数据通道

共享内存是核间通信中带宽最高、延迟最低的方式。其基本原理是:多个 CPU 核访问同一块物理内存区域,通过读写该区域实现数据交换。在 VxWorks 中,共享内存通常通过 mmap 或 vmMap 将同一物理地址映射到不同核的虚拟地址空间。

共享内存本身不提供同步机制,必须配合信号量或自旋锁使用。典型场景是:核 A 将采集数据写入共享缓冲区,核 B 从缓冲区读取并处理。为避免读写冲突,通常采用双缓冲区(Ping-Pong Buffer)或环形缓冲区结构。例如,定义一个包含 volatile int head、volatile int tail 和 char data[4096] 的环形队列,生产者核更新 head,消费者核更新 tail,通过内存屏障(VX_MEM_BARRIER())保证写入顺序可见。

共享内存的优点是零拷贝、高吞吐,适合传输大块数据(如图像帧、采样波形)。缺点是编程复杂,需要手动处理缓存一致性(Cache Coherency)。在 VxWorks 中,若共享区域被缓存,必须使用 cacheFlush 和 cacheInvalidate 确保数据可见性,或将该区域映射为非缓存(Uncached)属性。

消息队列:结构化、异步的核间消息传递

VxWorks 的消息队列(msgQ)支持核间通信,通过 msgQCreate 创建队列,msgQSend 发送消息,msgQReceive 接收消息。消息队列是异步的:发送方将消息放入队列后立即返回,接收方在需要时取出。消息队列支持优先级:高优先级消息可以插队到队列头部。

消息队列适合传递小尺寸、结构化的控制消息,如命令、状态更新、事件通知。其缺点是每次发送和接收都涉及内核调用和数据拷贝,延迟高于共享内存。在核间场景中,消息队列通常基于共享内存实现,VxWorks 内部使用自旋锁保护队列头尾指针。

一个典型配置示例:创建消息队列时指定最大消息数为 64,每条消息最大 256 字节。发送方使用 msgQSend(qid, &msg, sizeof(msg), WAIT_FOREVER, MSG_PRI_NORMAL),接收方使用 msgQReceive(qid, &msg, sizeof(msg), WAIT_FOREVER)。若队列满,发送方阻塞;若队列空,接收方阻塞。这种阻塞语义在实时系统中需要谨慎使用,通常配合超时参数避免死锁。

管道:字节流式的核间通信

管道(Pipe)在 VxWorks 中提供一种字节流式的通信方式,类似于 UNIX 管道。核间管道通过 pipeDevCreate 创建,使用 write 和 read 进行读写。管道是半双工的,数据按 FIFO 顺序流动,没有消息边界。

管道适合传输连续的字节流,如日志输出、串口数据转发。其优点是接口简单,与文件 I/O 类似;缺点是缺乏消息边界,接收方需要自行解析数据帧。在核间场景中,管道的性能通常低于共享内存和消息队列,因为每次读写都涉及内核缓冲区的拷贝。

信号量:核间同步与互斥的基石

信号量(Semaphore)是 VxWorks 中最基础的同步原语,分为二进制信号量、计数信号量和互斥信号量。在核间通信中,信号量主要用于保护共享资源、实现任务同步和事件通知。

VxWorks 提供 semBCreate、semCCreate 和 semMCreate 分别创建二进制、计数和互斥信号量。核间信号量通常基于共享内存中的原子操作实现,VxWorks 使用 semTake 和 semGive 进行获取和释放。互斥信号量支持优先级继承,可避免优先级反转。

在核间场景中,信号量常用于:保护共享内存缓冲区、通知数据就绪、实现生产者-消费者同步。例如,生产者核写入数据后 semGive 一个二进制信号量,消费者核 semTake 后读取数据。信号量的开销远低于消息队列,适合高频同步操作。

IPC 组件选型:从需求到决策

选择 IPC 机制时,需要综合考虑数据量、实时性、同步需求和编程复杂度。下表给出选型参考:

IPC 机制 数据量 延迟 同步方式 典型场景
共享内存 大块数据 最低 需配合信号量/自旋锁 图像帧、采样波形
消息队列 小消息 中等 阻塞/非阻塞 命令、事件通知
管道 字节流 中等偏高 阻塞/非阻塞 日志、串口转发
信号量 无数据 低 同步/互斥 资源保护、任务同步

选型决策可遵循以下原则:若需要传输大块数据且对延迟敏感,优先选择共享内存加信号量;若需要传递结构化控制消息且希望解耦发送和接收,选择消息队列;若需要字节流式通信且接口简单,选择管道;若仅需同步或互斥,选择信号量。

实践建议:在 VxWorks 多核系统中,共享内存区域应使用 cacheDmaMalloc 或 memPartAlloc 分配,并确保映射到所有相关核。使用信号量保护共享内存时,优先选择互斥信号量以支持优先级继承。对于高频小消息,可考虑使用无锁环形队列配合内存屏障,避免信号量开销。
VxWorks 核间通信机制选型决策图 CPU Core A 生产者 / 发送方 CPU Core B 消费者 / 接收方 共享内存区域 环形缓冲区 / 双缓冲区 需配合信号量或自旋锁 写入 读取 消息队列 msgQ 结构化消息 · 异步 · 支持优先级 msgQSend msgQReceive 管道 Pipe 字节流 · FIFO · 无消息边界 write read 信号量 semTake / semGive 保护 数据写入 数据读取 同步保护 共享内存带宽最高,消息队列结构化,管道字节流,信号量用于同步

在实际工程中,往往需要组合使用多种 IPC 机制。例如,一个典型的雷达信号处理系统:采集核通过共享内存将原始回波数据写入环形缓冲区,用二进制信号量通知处理核;处理核完成 FFT 后,通过消息队列将检测结果发送给显示核;显示核通过管道将日志输出到串口。这种组合方式兼顾了带宽、实时性和编程灵活性。

需要特别注意的是,核间通信的调试比单核复杂得多。建议在开发初期使用 VxWorks 的 ipcom 工具或 wdb 调试器观察共享内存状态和信号量计数,确保没有竞态条件和死锁。对于高可靠性系统,还应考虑通信超时、缓冲区溢出和核间心跳检测等异常处理机制。