【Linux】Linux 进程通信:System V 共享内存(最快方案)C++ 封装实战 + 通信案例,4 类经典 Bug 快速修复

【Linux】Linux 进程通信:System V 共享内存(最快方案)C++ 封装实战 + 通信案例,4 类经典 Bug 快速修复
前言:欢迎各位光临本博客,这里小编带你直接手撕**,文章并不复杂,愿诸君**耐其心性,忘却杂尘,道有所长!!!!
在这里插入图片描述

IF’Maxue个人主页
 🔥 个人专栏:
《C语言》
《C++深度学习》
《Linux》
《数据结构》
《数学建模》

⛺️生活是默默的坚持,毅力是永久的享受。不破不立!

文章目录

二、System V共享内存:最快的进程间通信

System V是Linux内核支持的一套IPC(进程间通信)标准,其中共享内存是速度最快的IPC方式——因为数据直接存在“共享物理内存”中,进程读写无需拷贝(其他IPC如FIFO需要内核中转)。

1. System V共享内存核心概念

  • IPC本质:让不同进程“看到同一份资源”。共享内存的“资源”是一块物理内存,OS通过“页表”将这块物理内存映射到多个进程的虚拟地址空间中。
  • 优势:读写速度快(进程操作自己的虚拟地址,等同于操作共享物理内存,无内核拷贝)。
  • 劣势:无同步机制(比如两个进程同时写,会导致数据混乱,需配合其他IPC(如FIFO)实现同步)。

2. System V共享内存原理

(1)进程虚拟地址空间结构

每个进程都有独立的虚拟地址空间,分为内核区、栈、堆、共享库区等,默认情况下进程间的内存互不干扰。

image.png
(2)共享内存映射过程

OS通过3步让进程共享内存:

  1. OS在物理内存中开辟一块“共享物理内存”。
  2. 进程A的虚拟地址空间中,分配一块虚拟地址,通过“页表”映射到共享物理内存。
  3. 进程B的虚拟地址空间中,也分配一块虚拟地址,同样通过页表映射到同一块共享物理内存。
    最终效果:进程A写自己的虚拟地址,进程B读自己的虚拟地址,就能拿到相同的数据。
(3)共享内存的管理:先描述,再组织

OS用一个“内核结构体”(struct shmid_ds)描述共享内存的信息(如大小、权限、引用计数),再用链表/哈希表组织所有共享内存,方便管理。

引用计数:记录有多少进程正在使用这块共享内存。只有引用计数为0时,OS才会真正释放物理内存(避免进程还在使用时内存被删)。

image.png

3. System V共享内存核心接口

操作共享内存需4个核心接口:ftok(生成唯一key)、shmget(创建/获取共享内存)、shmat(将共享内存映射到进程虚拟地址)、shmdt(解除映射)、shmctl(管理共享内存,如删除)。

(1)生成唯一Key:ftok
  • 功能:将“文件路径”和“项目ID(proj_id)”组合成一个唯一的key_t类型值(key),用于标识共享内存(确保不同进程能找到同一块共享内存)。
    • pathname:必须是已存在的文件路径(比如"./")。
    • proj_id:1~255的整数(自定义,只要进程间一致即可)。
    • 返回值:成功返回key,失败返回-1。

示例:两个进程都用ftok("./", 100),会生成相同的key,从而找到同一块共享内存。

image.png


image.png

接口参数与返回值

image.png
(2)创建/获取共享内存:shmget
  • 功能:根据key,创建新的共享内存,或获取已存在的共享内存(返回一个“共享内存ID(shmid)”,后续操作都用shmid)。
    • key:由ftok生成的唯一标识。
    • size:共享内存的大小(必须是4KB的整数倍,OS按页分配内存,不足4KB会自动补齐)。
    • shmflg:标志位,常用组合:
      • IPC_CREAT:如果共享内存不存在,则创建;如果已存在,则获取。
      • IPC_CREAT | IPC_EXCL | 0664:如果共享内存已存在,则报错(确保创建的是全新的共享内存);0664是共享内存的权限(和文件权限一致)。
    • 返回值:成功返回shmid(非负整数),失败返回-1。

返回值说明

image.png

接口参数与返回值

image.png
(3)映射共享内存到进程:shmat
  • 功能:将shmid对应的共享内存,映射到当前进程的虚拟地址空间中,返回映射后的虚拟地址(进程通过这个地址读写共享内存)。
    • shmidshmget返回的共享内存ID。
    • shmaddr:指定映射到进程虚拟地址的哪个位置(一般设为NULL,让OS自动分配,避免冲突)。
    • shmflg:映射标志(一般设为0,默认权限)。
    • 返回值:成功返回映射后的虚拟地址(void*类型),失败返回(void*)-1

示例

image.png


image.png

接口参数与返回值

image.png
(4)解除映射:shmdt
  • 功能:将共享内存从当前进程的虚拟地址空间中“解绑”(不会删除共享内存,只是进程看不到它了)。
    • shmaddrshmat返回的虚拟地址(必须和映射时的地址一致)。
    • 返回值:成功返回0,失败返回-1。
  • 注意:解除映射后,共享内存的“引用计数”会减1;若引用计数变为0,OS也不会立刻删除共享内存(需调用shmctl删除)。

接口参数与返回值

image.png
(5)管理共享内存:shmctl
  • 功能:对共享内存进行管理,如查看信息、修改权限、删除共享内存(最常用的是删除)。
    • shmidshmget返回的共享内存ID。
    • cmd:命令,常用IPC_RMID(删除共享内存)。
    • buf:指向struct shmid_ds的指针(用于传递/接收共享内存的信息,删除时可设为NULL)。
    • 返回值:成功返回0,失败返回-1。
    • 注意:调用shmctl(shmid, IPC_RMID, NULL)后,共享内存会被“标记为删除”,但不会立刻消失——直到所有进程都shmdt解除映射(引用计数为0),OS才会真正释放物理内存。

删除共享内存示例

image.png

接口参数与返回值

image.png

4. 共享内存实战:查看与删除(命令行)

(1)查看系统中的共享内存:ipcs -m
  • 功能:列出当前系统中所有System V共享内存的信息,包括shmid、key、大小、引用计数等。
    • shmid:共享内存ID(删除时用)。
    • keyftok生成的标识。
    • owner:创建共享内存的用户。
    • segsz:共享内存大小(4KB的整数倍)。
    • nattch:引用计数(当前有多少进程映射了这块内存)。

示例

image.png
(2)删除共享内存:ipcrm -m shmid
  • 功能:根据shmid删除共享内存(等同于代码中的shmctl(shmid, IPC_RMID, NULL))。
    • 注意:共享内存的生命周期“随内核”——即使创建它的进程退出,共享内存也会留在系统中(需手动ipcrm删除,或代码中shmctl删除),避免内存泄漏。

示例

image.png

5. 共享内存实战:Server与Client通信

(1)封装共享内存类(Shm.hpp)

为简化代码,用C++类封装共享内存的操作(创建/获取、映射、读写、删除)。

删除共享内存:提供Destroy(调用shmctl)成员函数,在析构函数中调用Detach

image.png

映射与解除映射:提供Attach(调用shmat)和Detach(调用shmdt)成员函数。

image.png

shmget失败(比如共享内存已存在),报错信息如下:

image.png

创建/获取共享内存:在构造函数中调用ftokshmget

image.png
(2)服务器端(server.cc):读共享内存

核心逻辑:创建共享内存 → 映射到虚拟地址 → 循环读数据 → 解除映射 → 删除共享内存。
代码示例:

image.png


image.png
(3)客户端(client.cc):写共享内存

核心逻辑:获取已存在的共享内存 → 映射到虚拟地址 → 写数据 → 解除映射(无需删除共享内存)。
代码示例:

image.png
(4)通信效果

客户端写入数据后,服务器能立刻读到共享内存中的内容(无需内核中转,速度极快)。

image.png

6. 共享内存的同步问题与解决

共享内存本身没有同步机制——如果服务器还没读,客户端就写了新数据,会覆盖旧数据;如果两个进程同时写,会导致数据混乱。

解决方法:结合FIFO实现同步(用FIFO作为“信号通道”,控制读写顺序)。
核心思路:

  1. 创建一个FIFO(同步通道)。
  2. 客户端:写共享内存 → 向FIFO写一个“信号”(比如1字节)。
  3. 服务器:从FIFO读“信号”(阻塞等待) → 读共享内存。
    这样就能确保“客户端写完,服务器才读”,避免数据覆盖。
(1)同步通道(FIFO)创建
image.png
(2)服务器端(同步读)

服务器先从FIFO读“信号”(阻塞等待客户端写完),再读共享内存。

image.png


image.png
(3)客户端(同步写)

客户端先写共享内存,再向FIFO写“信号”(唤醒服务器读)。

image.png


image.png

7. 常见问题与Bug解决

(1)权限拒绝(Permission denied)

调用shmat时若报错“权限拒绝”,是因为共享内存的权限不足(创建时shmflg没加权限)。
Bug效果:

image.png


解决方法:创建共享内存时,在shmflg中加上权限(如0664)。

image.png


修改后效果(映射成功):

image.png
(2)共享内存大小不是4KB整数倍

OS按“页”(4KB)分配共享内存,若size不是4KB的整数倍,OS会自动向上补齐(比如size=4097,实际分配8192字节)。
ipcs -m查看时,segsz会显示用户设置的size(而非补齐后的大小),容易误导。

image.png


建议:创建共享内存时,手动将size设为4KB的整数倍(比如size=4096size=8192),避免浪费。

(3)sleep导致的同步问题

若用sleep控制读写顺序(比如客户端sleep(1)后写,服务器sleep(2)后读),可能因时间差导致同步失败(比如sleep时间不够,服务器还没准备好,客户端就写了)。
Bug效果:

image.png


解决方法:不用sleep,改用FIFO等同步机制(如前所述),确保“写后再读”。

image.png
(4)共享内存删除后仍能访问

调用shmctl(shmid, IPC_RMID, NULL)后,共享内存被“标记为删除”,但只要有进程还在映射(引用计数>0),进程仍能访问它;只有所有进程都shmdt后,共享内存才会真正消失。
示例:服务器删除共享内存后,客户端仍能读数据(直到客户端shmdt)。

image.png


image.png


image.png

8. 共享内存的内核数据结构(补充)

OS用struct shmid_ds描述共享内存的详细信息,这个结构体包含以下核心字段:

image.png
  • shm_perm:权限相关信息(如所有者、组、权限)。
  • shm_segsz:共享内存大小(用户设置的size)。
  • shm_nattch:引用计数(当前映射的进程数)。
  • shm_atime:最后一次shmat的时间。
  • shm_dtime:最后一次shmdt的时间。
  • shm_ctime:最后一次修改(如权限、大小)的时间。

当调用shmget创建共享内存时,OS会初始化这个结构体,并将key存入shm_perm.__key字段,用于标识共享内存。

image.png


image.png

Read more

VSCode Github Copilot使用OpenAI兼容的自定义模型方法

VSCode Github Copilot使用OpenAI兼容的自定义模型方法

背景 VSCode 1.105.0发布了,但是用户最期待的Copilot功能却没更新!!! (Github Copilot Chat 中使用OpenAI兼容的自定义模型。) 🔥官方也关闭了Issue,并且做了回复,并表示未来也不会更新这个功能: “实际上,这个功能在可预见的未来只面向内部人员开放,作为一种“高级”实验功能。是否实现特定模型提供者的功能,我们交由扩展作者自行决定。仅限内部人员使用可以让我们快速推进,并提供一种可能并非始终百分之百完善,但能够持续改进并快速修复 bug 的体验。如果这个功能对你很重要,我建议切换到内部版本 insider。” 🤗 官方解决方案:安装VSCode扩展支持 你们完全不用担心只需要在 VS Code 中安装扩展:OAI Compatible Provider for Copilot 通过任何兼容 OpenAI 的提供商驱动的 GitHub Copilot Chat,使用前沿开源大模型,如 Kimi K2、DeepSeek

By Ne0inhk
GitHub,Gitee,qq 第三方登录配置完整教程

GitHub,Gitee,qq 第三方登录配置完整教程

GitHub 第三方登录配置完整教程 本教程将详细介绍如何在博客系统中集成 GitHub 第三方登录功能,包括 GitHub OAuth App 创建、前后端配置、代码实现等,适合零基础小白学习。 📚 目录 1. 什么是 GitHub 第三方登录 2. 创建 GitHub OAuth App 3. 后端配置 4. 前端配置 5. 代码实现详解 6. 测试登录 7. 常见问题 什么是 GitHub 第三方登录 GitHub 第三方登录(OAuth 2.0)允许用户使用 GitHub 账号登录你的网站,无需注册新账号。用户点击"GitHub 登录"

By Ne0inhk
Git下载及安装保姆级教程(内附快速下载方法)!

Git下载及安装保姆级教程(内附快速下载方法)!

Git 下载及安装保姆级教程(适用于 Windows/macOS/Linux),含详细步骤和避坑指南: 一、下载 Git 1. Windows 用户 官方下载地址:https://git-scm.com/download/win (自动识别系统位数,点击下载 64-bit Git for Windows Setup) PS:由于一些原因,Git安装包下载速度较慢,可以复制资源链接下载本文的资源 https://pan.q删掉憨子uark.cn/s/8c425974eae3 2. macOS 用户 * 方法2: 下载官方安装包:https://git-scm.com/download/mac 方法1(推荐): 打开终端 → 安装

By Ne0inhk

永久开源免费用!科哥打造的OCR文字检测工具推荐

永久开源免费用!科哥打造的OCR文字检测工具推荐 一款真正开箱即用、无需配置、不收一分钱的OCR文字检测WebUI工具——它不只是一段代码,而是一个完整可交付的生产力解决方案。本文将带你从零开始,快速上手这款由科哥独立开发、持续维护的cv_resnet18_ocr-detection镜像,并深入理解它在真实工作流中能为你省下多少时间。 1. 为什么你需要这个OCR工具? 你是否也经历过这些时刻: * 扫描合同后想快速提取条款,却要反复截图、粘贴、校对; * 整理上百张发票照片,手动录入金额和日期,一坐就是半天; * 做竞品分析时,看到对手宣传页上的关键数据,却没法一键复制; * 学生党整理课堂PPT截图,逐张打字转文字,效率低到怀疑人生。 市面上的OCR服务,要么按次收费、要么限制调用量、要么需要注册企业资质、要么部署复杂得像在搭火箭。而今天介绍的这款工具,没有试用期、没有水印、不联网上传、不依赖云服务、不强制绑定账号——它就安静地运行在你的服务器或本地机器上,点开浏览器就能用。 更关键的是:它不是简单套壳,而是基于ResNet18主干网络+优化检测头的轻量级OC

By Ne0inhk