用 System V 共享内存实现本机高速 IPC:从原理到可运行环形队列
在 Linux 系统里进程隔离是默认安全边界每个进程拥有独立虚拟地址空间一个进程不能直接读写另一个进程的普通内存。这个设计让程序更安全但也带来了进程间通信的问题。常见 IPC 方式包括管道、Unix Domain Socket、TCP Socket、消息队列、mmap 共享映射以及 System V 共享内存。如果两个本机进程需要频繁交换大量数据例如采集进程把日志片段交给分析进程、媒体进程把帧元数据交给编码进程、交易网关把行情快照传给策略进程Socket 和管道都能工作但数据通常要经历内核缓冲区拷贝和系统调用调度。共享内存的核心优势是多个进程把同一段物理内存映射到自己的虚拟地址空间后可以像访问普通数组一样读写同一块数据区。共享内存并不自动解决所有问题。它只解决“数据放在哪里”不解决“谁先写、谁后读、写到一半能不能被读、进程退出后资源如何清理”等问题。工程上真正容易出错的地方往往不是 shmget 或 shmat 的调用而是生命周期、同步协议和异常恢复。本文以 System V 共享内存为主线写一个最小但可执行的单生产者单消费者环形队列帮助你理解它适合什么场景、如何落地、以及哪些坑不能忽略。原理解释System V 共享内存的使用流程可以分为四步。第一步通过ftok生成 key或直接约定一个key_t。key 是创建和查找共享内存段的标识不是内存地址。第二步通过shmget创建或获取共享内存段。它返回一个shmid后续进程可以用这个 ID 绑定共享内存。第三步通过shmat把共享内存段挂载到当前进程地址空间。调用成功后会得到一个指针进程可以通过这个指针读写共享区域。第四步通过shmdt分离共享内存通过shmctl(..., IPC_RMID, ...)标记删除共享内存段。注意IPC_RMID并不等于立刻强制解除所有已挂载进程的映射它表示当最后一个进程分离后内核可以回收该段资源。共享内存的问题在于多个进程可以同时读写同一段内存。如果没有同步读进程可能读到半条消息写进程可能覆盖未消费数据。同步可以使用 System V 信号量、POSIX 信号量、pthread 进程共享锁、eventfd、futex 等方式。为了让示例聚焦本文用 C11 原子变量实现一个单生产者单消费者模型只有一个 writer 和一个 reader因此可以用 head/tail 下标配合 acquire/release 内存序完成基本同步。这个限制很重要下面的队列不是多生产者多消费者队列。如果你有多个写进程或多个读进程需要引入互斥锁、信号量或更复杂的无锁算法。可执行步骤1. 准备目录mkdir-psysv-shm-ringcdsysv-shm-ring2. 编写公共头文件创建ring.h#ifndefRING_H#defineRING_H#includestdatomic.h#includestddef.h#includestdint.h#defineRING_CAPACITY64#defineMESSAGE_SIZE256structring_slot{chardata[MESSAGE_SIZE];};structshm_ring{atomic_uint head;atomic_uint tail;structring_slotslots[RING_CAPACITY];};#defineSHM_PROJ_ID65#defineSHM_SIZEsizeof(structshm_ring)#endif这里的head表示下一个要写入的位置tail表示下一个要读取的位置。为了区分“空”和“满”环形队列会浪费一个槽位当(head 1) % RING_CAPACITY tail时认为队列已满。3. 编写生产者创建producer.c#includering.h#includeerrno.h#includestdio.h#includestdlib.h#includestring.h#includesys/ipc.h#includesys/shm.h#includeunistd.hstatickey_tbuild_key(void){key_tkeyftok(.,SHM_PROJ_ID);if(key-1){perror(ftok);exit(1);}returnkey;}intmain(void){intshmidshmget(build_key(),SHM_SIZE,IPC_CREAT|0600);if(shmid-1){perror(shmget);return1;}structshm_ring*ringshmat(shmid,NULL,0);if(ring(void*)-1){perror(shmat);return1;}atomic_store_explicit(ring-head,0,memory_order_release);atomic_store_explicit(ring-tail,0,memory_order_release);for(unsignedi0;i20;i){while(1){unsignedheadatomic_load_explicit(ring-head,memory_order_relaxed);unsignedtailatomic_load_explicit(ring-tail,memory_order_acquire);unsignednext(head1)%RING_CAPACITY;if(nexttail){usleep(1000);continue;}snprintf(ring-slots[head].data,MESSAGE_SIZE,message-%u,i);atomic_store_explicit(ring-head,next,memory_order_release);printf(produced: message-%u\n,i);break;}}shmdt(ring);return0;}生产者先创建共享内存再初始化队列下标然后循环写入消息。这里用memory_order_release发布 head保证消费者看到新的 head 时也能看到对应槽位里的消息内容。4. 编写消费者创建consumer.c#includering.h#includestdio.h#includestdlib.h#includestring.h#includesys/ipc.h#includesys/shm.h#includeunistd.hstatickey_tbuild_key(void){key_tkeyftok(.,SHM_PROJ_ID);if(key-1){perror(ftok);exit(1);}returnkey;}intmain(void){intshmidshmget(build_key(),SHM_SIZE,0600);if(shmid-1){perror(shmget);return1;}structshm_ring*ringshmat(shmid,NULL,0);if(ring(void*)-1){perror(shmat);return1;}for(unsignedcount0;count20;){unsignedtailatomic_load_explicit(ring-tail,memory_order_relaxed);unsignedheadatomic_load_explicit(ring-head,memory_order_acquire);if(tailhead){usleep(1000);continue;}printf(consumed: %s\n,ring-slots[tail].data);unsignednext(tail1)%RING_CAPACITY;atomic_store_explicit(ring-tail,next,memory_order_release);count;}shmdt(ring);return0;}消费者通过同一个 key 找到共享内存段。读取 head 使用 acquire 语义保证读取到生产者发布的 head 后可以安全读取该 head 之前写入的消息。5. 编写清理工具共享内存是内核对象进程退出后不一定自动删除。创建cleanup.c#includering.h#includestdio.h#includestdlib.h#includesys/ipc.h#includesys/shm.hintmain(void){key_tkeyftok(.,SHM_PROJ_ID);if(key-1){perror(ftok);return1;}intshmidshmget(key,SHM_SIZE,0600);if(shmid-1){perror(shmget);return1;}if(shmctl(shmid,IPC_RMID,NULL)-1){perror(shmctl);return1;}puts(shared memory marked for removal);return0;}6. 编写 MakefileCC ? gcc CFLAGS : -stdc11 -O2 -Wall -Wextra -pedantic all: producer consumer cleanup producer: producer.c ring.h $(CC) $(CFLAGS) -o producer producer.c consumer: consumer.c ring.h $(CC) $(CFLAGS) -o consumer consumer.c cleanup: cleanup.c ring.h $(CC) $(CFLAGS) -o cleanup cleanup.c clean: rm -f producer consumer cleanup7. 编译和运行make./producer ./consumer ./cleanup更接近真实通信的运行方式是打开两个终端。先启动生产者或消费者都可以但如果先启动消费者共享内存必须已经存在。因此可以先运行一次生产者或把消费者里的shmget改成带IPC_CREAT的创建逻辑并增加初始化状态字段避免消费者读到未初始化队列。也可以用系统命令观察共享内存段ipcs-m如果调试期间进程异常退出清理工具无法定位资源可以用ipcrm按 shmid 删除。但在线上环境不要随手删除不认识的共享内存段先确认 owner、权限和业务归属。工程化改进上面的示例刻意保持简单适合理解机制但生产环境至少要补上四类能力。第一初始化协议。共享内存段可能由任意进程先创建因此不能假设第一个 attach 的进程一定是生产者。常见做法是在共享内存头部放magic、version、initialized字段并用文件锁或信号量保护初始化过程。第二阻塞通知。示例用usleep轮询简单但不优雅。低延迟场景可能接受短暂自旋普通服务更适合用 semaphore、eventfd 或条件变量减少空转。第三数据格式版本。共享内存里的结构体是二进制契约字段顺序、对齐方式、大小端、编译器 ABI 都会影响兼容性。跨版本升级时不要直接改结构体含义应保留版本号、长度字段和向后兼容策略。第四异常恢复。生产者写入一半崩溃时消费者如何判断槽位是否有效一种方式是给每个槽位增加 sequence 或 committed 标记写入完成后再发布状态读取端只消费完整提交的数据。常见问题共享内存是不是一定比 Socket 快不一定。共享内存减少了数据拷贝但同步、缓存一致性、错误恢复和协议复杂度都要自己承担。小消息、低频调用、跨机器通信或安全隔离要求高的场景Socket 往往更简单、更稳妥。共享内存更适合本机进程之间传递高频、大块、结构稳定的数据。为什么示例不用字符串拼接协议共享内存不是字节流而是一块双方约定布局的内存。使用固定大小槽位可以让示例更清晰避免长度字段、内存碎片和变长消息回收问题。真实系统如果要支持变长消息可以采用“共享内存存数据 队列传 offset/length”的设计。shmctl(..., IPC_RMID, ...)会不会影响正在使用的进程已经 attach 的进程通常仍可继续访问直到它们 detach 或退出但新的 attach 行为会受影响。实际策略要结合系统行为和业务生命周期设计不要把 IPC_RMID 当成普通内存 free 来理解。可以把指针放进共享内存吗不要直接放普通进程内指针。不同进程 attach 到的虚拟地址可能不同某个进程里的地址在另一个进程中没有意义。共享内存里应存 offset、索引或固定布局数据。如果确实要表达引用关系用相对偏移更可靠。多个生产者能复用这个代码吗不能直接复用。这个实现只针对单生产者单消费者。多个生产者同时写 head 会产生竞争必须引入锁、CAS 循环、槽位序列号或其他并发控制机制。不要只把 atomic 加上就认为多进程并发已经安全。总结System V 共享内存的价值在于让本机多个进程直接访问同一段内存适合高频、大块、低拷贝的 IPC 场景。但它只提供共享存储不提供完整通信协议。一个可靠实现必须同时考虑初始化、同步、内存可见性、资源清理、版本兼容和异常恢复。如果只是学习机制可以从本文的环形队列开始如果要用于生产建议把共享内存视为一份严格的二进制接口契约像设计网络协议一样设计字段、状态和升级路径。共享内存本身不复杂复杂的是把它放进真实系统后仍然可维护、可排障、可恢复。

相关新闻

如何零成本获取全球金融数据:AKShare Python财经数据接口库完整指南

如何零成本获取全球金融数据:AKShare Python财经数据接口库完整指南

如何零成本获取全球金融数据:AKShare Python财经数据接口库完整指南 【免费下载链接】akshare AKShare is an elegant and simple financial data interface library for Python, built for human beings! 开源财经数据接口库 项目地址: https://gitcode.com/gh_m…

2026/8/3 13:25:25 阅读更多 →
PKA多肽抑制剂6-22的作用机制与实验应用指南

PKA多肽抑制剂6-22的作用机制与实验应用指南

1. 项目概述:多肽抑制剂6-22的分子特性与应用价值这个由18个氨基酸组成的多肽序列(TYADFIASGRTGRRNAI-NH2)是蛋白激酶A(PKA)的特异性抑制剂,在科研领域被称为"PKA Inhibitor (6-22), amide"。我第…

2026/8/3 13:25:25 阅读更多 →
Bilibili视频下载工具:让优质内容随时陪伴你的学习与生活

Bilibili视频下载工具:让优质内容随时陪伴你的学习与生活

Bilibili视频下载工具:让优质内容随时陪伴你的学习与生活 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 你是否曾在通勤地…

2026/8/3 13:24:24 阅读更多 →

最新新闻

3分钟解决所有Visual C++运行库问题:告别DLL缺失的终极方案

3分钟解决所有Visual C++运行库问题:告别DLL缺失的终极方案

3分钟解决所有Visual C运行库问题:告别DLL缺失的终极方案 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经在打开游戏或专业软件时&#xf…

2026/8/3 13:55:46 阅读更多 →
HMC773ALC3BTR,6~26GHz 无源混频器

HMC773ALC3BTR,6~26GHz 无源混频器

简介HMC773ALC3BTR是一款 GaAs 工艺双平衡无源基波混频器,专为高频上下变频场景打造,编带封装适配规模化 SMT 生产。这款器件工作射频、本振区间覆盖 6~26GHz,中频带宽直达直流至 8GHz,可同时实现发射端上变频、接收端下变频。核心…

2026/8/3 13:55:46 阅读更多 →
从开团手到护卫者:牛魔辅助的团队保护打法深度解析

从开团手到护卫者:牛魔辅助的团队保护打法深度解析

最近在整理对局复盘时,翻到一场1700分段的巅峰赛录像。这场对局里,我方辅助牛魔的操作让我印象很深——不是因为他打出了多么华丽的开团,恰恰相反,他整场都在做一件看起来“很怂”的事:用二技能“横行霸道”的位移&…

2026/8/3 13:55:46 阅读更多 →
【金仓数据库征文】文档数据迁移后的完整性核验——异构迁移中的数据校验与差异分析实践

【金仓数据库征文】文档数据迁移后的完整性核验——异构迁移中的数据校验与差异分析实践

文章目录每日一句正能量1. 背景与问题2. 环境与数据3. 复现过程4. 方案实施数据总量校验JSON 字段校验Hash 校验多模型联合查询差异报告设计5. 结果对比6. 风险与复盘风险建议总结每日一句正能量 每条路上都有它的荆棘和风雨,你没选的那条路未必就开满鲜花。 我们总…

2026/8/3 13:55:46 阅读更多 →
Jetson Nano J401载板刷写JetPack OS全流程与避坑指南

Jetson Nano J401载板刷写JetPack OS全流程与避坑指南

1. 项目概述:为Jetson Nano载板注入灵魂最近在折腾一个边缘计算项目,手头有一块英伟达Jetson Nano开发者套件自带的J401载板。这块板子本身只是个“躯壳”,其核心——Jetson Nano模组(SoM)——需要一套完整的操作系统才…

2026/8/3 13:55:45 阅读更多 →
Python Pygame实战:从零开发“消灭病毒”2D射击游戏

Python Pygame实战:从零开发“消灭病毒”2D射击游戏

1. 项目概述与核心价值最近在整理自己的代码仓库,翻出来一个几年前用Python写的“消灭病毒”小游戏。这个项目当时是为了给几个刚学Python的朋友做演示,没想到后来成了我讲解游戏开发基础、Python面向对象编程以及Pygame库使用的经典案例。今天&#xff…

2026/8/3 13:54:40 阅读更多 →

日新闻

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描/生成二维码。…

2026/8/3 0:00:47 阅读更多 →
[具身智能-181]:PC+服务器+具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构

[具身智能-181]:PC+服务器+具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构

PC服务器具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构一、前言:具身智能需要“混合算力闭环系统”传统人工智能依赖云端静态数据集训练,不具备物理交互能力,无法适应真实世界的不确定性。具身智能(Embodied…

2026/8/3 0:00:47 阅读更多 →
[具身智能-181]:大分布式通信模型对比:看懂为什么 DDS 是 ROS2 底层通信最优解

[具身智能-181]:大分布式通信模型对比:看懂为什么 DDS 是 ROS2 底层通信最优解

前言构建机器人、具身智能这类分布式实时系统,通信底座直接决定整套系统的实时性、容错性、组网能力。分布式领域长期存在 4 类经典通信架构:点对点模式、Broker 中间代理模式、广播模式、以数据为中心(DDS)模式。很多开发者疑惑&…

2026/8/3 0:00:47 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/3 4:58:13 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/3 1:53:31 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/3 4:36:35 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/3 13:07:03 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/3 5:19:38 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/3 8:27:36 阅读更多 →