1. 共享内存基础:VxWorks SMP架构概述、共享内存的概念与原理、物理内存与虚拟内存映射

好,咱们开始第一讲。共享内存,说白了就是让多个核能看见同一块数据。这个概念听起来简单,但实际用起来坑不少。我做了这么多年嵌入式,见过太多因为共享内存没处理好导致系统崩溃的案例。今天咱们就把这个基础打牢。

1.1 VxWorks SMP架构概述

SMP,对称多处理。什么意思?就是所有CPU核心地位平等,共享同一份内存空间,跑同一个操作系统。你想想看,四个核就像四个工人,都在同一个车间里干活,工具(内存)是共用的。

在VxWorks SMP系统中,每个核都有自己的寄存器组和缓存,但物理内存是统一的。系统启动时,VxWorks会检测到有多少个核可用,然后统一调度任务到各个核上运行。

核心特点:

  • 所有核共享同一个内存地址空间
  • 操作系统统一管理所有核
  • 任务可以在任意核上调度执行
  • 核间通过共享内存和中断通信

我记得刚接触SMP时,总觉得多核就是多个单核拼一起。后来踩了坑才发现,事情没那么简单。核间缓存一致性问题、任务迁移的开销、锁竞争,这些都是SMP特有的麻烦。

1.2 共享内存的概念与原理

共享内存,就是一块可以被多个进程或线程同时访问的内存区域。在VxWorks中,共享内存通常用于核间通信(IPC)和数据交换。

为什么会需要共享内存?我给你举个例子。假设核0采集了传感器数据,核1要做数据处理。如果没有共享内存,你就得用消息队列或者管道来传数据。但消息队列有拷贝开销,数据量大时性能很差。共享内存就不一样了,数据写进去,另一个核直接读,零拷贝。

我的经验:在项目中,如果数据交换频率高、数据量大,我一般优先考虑共享内存。消息队列适合小数据量、低频次的通信。

共享内存的工作原理其实不复杂:

  1. 一块物理内存被映射到多个进程的地址空间
  2. 一个进程写数据,另一个进程直接看到变化
  3. 需要同步机制(如信号量)来防止数据竞争

嗯,这里要注意:共享内存本身不提供同步机制。你写我读,如果不同步,读到的可能是半成品数据。我曾经在一个项目中,两个核共享一个结构体,没加锁,结果读到的数据总是错乱的。排查了两天才发现问题。

1.3 物理内存与虚拟内存映射

这个知识点,很多初学者容易搞混。物理内存是硬件上真实存在的内存条。虚拟内存是每个进程看到的假想地址空间。VxWorks通过MMU(内存管理单元)把虚拟地址翻译成物理地址。

在SMP系统中,所有核共享同一个物理内存。但每个核的虚拟地址空间是独立的吗?不一定。VxWorks中,内核空间是所有核共享的,用户空间则取决于配置。

概念 说明 我踩过的坑
物理地址 硬件内存的真实地址 直接操作物理地址要小心,容易崩系统
虚拟地址 CPU看到的地址,经过MMU转换 不同进程的虚拟地址相同,但物理地址不同
映射关系 虚拟→物理的对应表 映射错了,写数据会写到奇怪的地方

在VxWorks中,共享内存的创建通常涉及以下步骤:

/* 分配物理连续内存 */
PHYS_MEM_ADDR physAddr = cacheDmaMalloc(size);

/* 将物理内存映射到虚拟地址空间 */
void *virtAddr = (void *)vmMap(NULL, physAddr, size, 
                               VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE,
                               VM_STATE_VALID | VM_STATE_WRITABLE);

/* 其他核通过相同物理地址映射 */
void *otherVirtAddr = (void *)vmMap(NULL, physAddr, size, 
                                    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE,
                                    VM_STATE_VALID | VM_STATE_WRITABLE);

警告:共享内存的物理地址必须对所有核可见。有些平台的内存区域是核私有的,比如某些ARM核的TCM(紧耦合内存),不能用作共享内存。

我个人习惯在项目初期就把物理内存布局画清楚。哪块内存给核0用,哪块给核1用,哪块是共享的。画清楚了,后面少很多麻烦。

还有一个容易忽略的点:缓存一致性。当核0写共享内存时,数据可能还在自己的缓存里,没有刷回主存。核1去读主存,读到的是旧数据。解决办法是使用缓存一致性协议(如MESI),或者手动刷缓存。

/* 写共享内存后,刷缓存 */
CACHE_FLUSH(sharedAddr, size);

/* 读共享内存前,使缓存失效 */
CACHE_INVALIDATE(sharedAddr, size);

我曾经在一个项目中,就是因为忘了刷缓存,两个核之间通信总是丢数据。查了三天,最后发现是缓存没刷。从那以后,我写共享内存代码,第一件事就是加上缓存操作。

小结

这一章咱们讲了三个核心概念:SMP架构、共享内存原理、物理虚拟内存映射。说白了,共享内存就是让多核能高效交换数据的手段。但高效是有代价的——你得处理好同步、缓存一致性和地址映射这些细节。

下一章,咱们会深入讲共享内存的创建和配置,包括VxWorks提供的API和实际代码示例。到时候我会拿一个真实项目中的例子来讲解,保证你能用得上。