2. 操作系统基础回顾

在多 OS 共享内存与跨域通信的工程实践中,所有上层机制最终都要落到操作系统的资源抽象与隔离能力上。共享内存之所以“共享”,是因为多个执行体映射了同一段物理页;跨域通信之所以“跨域”,是因为数据要跨越进程边界、地址空间边界,甚至 CPU 特权级边界。理解进程、线程、虚拟内存、地址空间、内核态与用户态、系统调用与中断,是后续设计共享内存布局、同步协议和通信通道的前提。

一、进程与线程:资源容器与执行单元

进程是操作系统进行资源分配的基本单位,它拥有独立的虚拟地址空间、文件描述符表、信号处理表、凭证信息等。线程是 CPU 调度的基本单位,同一进程内的多个线程共享地址空间和大部分资源,但各自拥有独立的栈、寄存器上下文和线程局部存储。这个区别直接决定了共享内存的访问方式:同一进程内的线程可以直接通过指针访问共享段;不同进程之间则必须先把同一物理内存映射到各自的虚拟地址空间,再通过约定的偏移或句柄来访问。

在跨域通信中,常见模型是“一个进程内多线程 + 多进程共享内存”。线程负责并发处理,进程负责隔离与容错。若把共享内存放在进程私有堆上,其他进程无法直接访问;只有通过 shm_open、mmap、CreateFileMapping 等系统调用建立共享映射,才能形成跨进程可见的内存区域。

二、虚拟内存与地址空间:隔离与映射

虚拟内存为每个进程提供独立的连续地址空间幻觉。CPU 发出的地址是虚拟地址,经 MMU 和页表翻译为物理地址。页表项中记录物理页框号、权限位、有效位、脏位等。虚拟内存带来的关键能力包括:进程隔离、按需分页、内存映射文件、写时复制以及共享映射。

共享内存的本质,就是让多个进程的页表项指向同一组物理页框。每个进程看到的虚拟地址可以不同,但物理页相同。因此,跨进程共享内存不能传递“裸指针”,而应传递“共享段标识 + 偏移量”。这也是很多跨域通信框架使用句柄、偏移和描述符而不是绝对地址的原因。

关键结论:共享内存的“地址”只在单个进程内有意义;跨进程必须使用共享段 ID、偏移量或文件描述符来定位数据。

三、内核态与用户态:特权级边界

现代 CPU 通常划分多个特权级,操作系统运行在内核态,应用程序运行在用户态。用户态不能直接执行特权指令、访问内核页表或操作硬件寄存器;一旦需要访问硬件、创建映射、发送信号或进行进程间同步,就必须通过系统调用陷入内核。内核态与用户态的切换是有成本的,包括保存上下文、切换栈、检查参数、执行内核代码、返回用户态等。

共享内存的高效性正来自“建立映射后,数据读写不再陷入内核”。但同步、通知和生命周期管理仍可能需要系统调用或原子指令。工程上要区分“数据面”和“控制面”:数据面尽量在用户态完成,控制面才使用系统调用。

四、系统调用与中断机制

系统调用是用户态程序请求内核服务的标准入口。以 Linux 为例,应用通过 syscall 指令或库函数封装进入内核,内核根据系统调用号分发到具体处理函数。常见与共享内存相关的系统调用包括:

shm_open()     创建或打开 POSIX 共享内存对象
ftruncate()    设置共享内存对象大小
mmap()         将共享内存映射到进程地址空间
munmap()       解除映射
msync()        同步映射页到存储
shm_unlink()   删除共享内存对象

中断则分为硬件中断、软件中断和异常。硬件中断由外设触发,例如网卡收到数据包;软件中断常用于系统调用和延迟处理;异常包括缺页、除零、非法指令等。缺页异常与虚拟内存密切相关:当进程访问尚未映射或尚未调入的页时,CPU 触发缺页异常,内核负责分配物理页、读取文件或建立共享映射。共享内存首次访问时也可能触发缺页,把共享段页框映射进当前进程页表。

进程 / 虚拟内存 / 共享内存 / 特权级关系 用户态 进程 A 线程 A1 / A2 / A3 虚拟地址空间 A 页表 A → 物理页 进程 B 线程 B1 / B2 虚拟地址空间 B 页表 B → 物理页 共享内存段 shm_open + mmap 物理页框(同一组) 偏移量 / 句柄定位 内核态 系统调用接口 shm_open / mmap / munmap 虚拟内存管理 页表 / 缺页异常 / 物理页分配 中断与异常处理 硬件中断 / 软件中断 / 缺页 陷入内核 地址翻译 事件触发 数据面在用户态完成读写,控制面通过系统调用与中断进入内核

五、案例场景:两个进程通过共享内存通信

假设进程 A 是采集进程,进程 B 是分析进程。A 通过 shm_open 创建共享内存对象,ftruncate 设置大小,mmap 映射到自己的地址空间;B 通过同名对象打开并映射。两者页表指向同一组物理页。A 写入数据后,通过信号量或原子标志通知 B;B 读取后回写状态。整个过程数据读写不经过内核拷贝,只有同步和映射管理涉及系统调用。

概念 作用 与共享内存的关系
进程 资源分配与隔离单位 提供独立地址空间,共享内存需跨进程映射
线程 CPU 调度单位 同进程线程可直接访问共享段,需注意同步
虚拟内存 地址翻译与隔离 使不同虚拟地址映射到同一物理页
地址空间 进程可见的地址范围 共享内存需映射进各进程地址空间
内核态/用户态 特权级隔离 映射与同步需陷入内核,数据读写可在用户态
系统调用 用户态请求内核服务 shm_open、mmap、munmap 等建立共享映射
中断/异常 异步事件与错误处理 缺页异常触发共享页映射与调入

六、常见误区与复盘

  • 误区一:把虚拟地址当作跨进程标识。虚拟地址只在当前进程有效,跨进程必须使用共享段 ID 和偏移量。
  • 误区二:认为共享内存不需要同步。多个执行体并发读写同一物理页,必须使用信号量、互斥锁或原子操作保护。
  • 误区三:忽略缺页与映射时机。首次访问共享页可能触发缺页异常,实时性要求高的场景应提前预热或锁定页面。
  • 误区四:混淆线程共享与进程共享。线程共享地址空间,进程共享需要显式映射;两者的生命周期和错误隔离能力不同。
复盘要点:设计跨域通信时,先画清楚“谁映射了什么、虚拟地址是否相同、同步点在哪里、哪些操作会陷入内核”,再决定共享内存布局和通知机制。
注意:共享内存对象被 shm_unlink 后,已映射的进程仍可继续访问,直到解除映射;但新进程无法再打开。生命周期管理必须与业务状态机一致,避免悬空引用。