linux多线(进)程编程——(6)共享内存

news2025/5/15 19:13:11

前言

话说进程君的儿子经过父亲点播后就开始闭关,它想要开发出一种全新的传音神通。他想,如果两个人的大脑生长到了一起,那不是就可以直接知道对方在想什么了吗,这样不是可以避免通过语言传递照成的浪费吗?
下面就是它的设计思路。

共享内存

进程间的通信手段分别有:管道,共享内存,消息队列,信号,信号量,套接字。今天我们将学习第二种方式,共享内存(Shared Memory)。这也是进程间通信最为高效的方式。
共享内存的原理其实很简单,进程间由于操作系统的内存映射,实现了物理内存的隔离。如果有一种方法可以让两个进程的内存同时映射到一块物理内存上,那么这块内存内的数据就对两个进程全部可见了。我们也可以直接通过指针访问对应的内存空间实现进程间数据的高效传输。
共享内存的原理示意图

共享内存的使用

linux系统为共享内存提供了以下几个函数接口,它们以shm开头,表示Shared Memory
(1)向系统申请获取共享

int shmget(ket_t __key, size_t __size, int __shmflg);

这个函数用于向系统申请一块共享内存。
__key:共享内存的键值,这个键值用于在不同进程间标识为一的共享功能区
__size:共享内存的大小(单位:字节),对于相同键值,大小要保持一致
__shmflg:共享内存申请方式
return val:返回共享内存的ID号

(2)挂载共享内存

void* shmat(int __shmid, const void *shmaddr, int __shmflg);

这个函数用于将共享内存挂载到进程内部的虚拟地址上,使用这个函数后就可以直接使用指针操作共享内存
__shmid:共享内存ID
__shmaddr:希望挂载到地址,为NULL由系统自行分配
__shmflg:一般值为0即可
return val:返回共享内存在进程中的虚拟地址的值

(3)分离共享内存

int shmdt(const void *__shmaddr);

这个函数用于将共享内存与进程的虚拟内存分离。
__shmaddr:指向共享内存的虚拟地址

(4)控制共享内存

int shmctl(int __shmid, int __command, struct shmid_ds *__buf);

用来对共享内存执行一些操作,用来告诉系统释放共享内存
__shmid:共享内存ID
__command:要执行的指令,为IPC_RMID时用来告诉系统释放共享内存
__buf:为NULL即可(高级用法一般用不到)

代码案例

运行两个程序,申请共享内存后一个写入hello world,另一个程序读取。
pro1.c:写入数据

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>

#define SHMSIZE 20		// 共享内存大小,与pro2.c保持一致,否则一定报错

int main() {
    int ID = shmget((key_t)1, SHMSIZE, 0666|IPC_CREAT);		// 申请共享内存,键值为1,与pro2.c保持一致
    char* shm_addr = shmat(ID, NULL, 0);	// 挂载到进程的虚拟内存地址上
    char str[SHMSIZE] = "hello, world!";	
    memcpy(shm_addr, str, sizeof(str));		// 使用指针 shm_addr 操作共享内存
    shmdt(shm_addr);						// 分离共享内存
    return 0;
}

pro2.c读取数据

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>

#define SHMSIZE 20 		// 共享内存大小,与pro1.c保持一致,否则一定报错

int main() {
    int ID = shmget((key_t)1, SHMSIZE, 0666|IPC_CREAT);		// 申请共享内存,键值为1,与pro2.c保持一致
    char* shm_addr = shmat(ID, NULL, 0);
    
    printf("%s\n", shm_addr); 		// 打印数据
    shmdt(shm_addr);
    shmctl(ID, IPC_RMID, NULL);		// 释放共享内存,不然即使关闭程序也会内存泄露,共享内存不会回收
    return 0;
}

运行结果

lol@hyl:~/work/linux_study/Shared_memory/shm_fun$ gcc -o p1 pro1.c
lol@hyl:~/work/linux_study/Shared_memory/shm_fun$ gcc -o p2 pro2.c
lol@hyl:~/work/linux_study/Shared_memory/shm_fun$ ./p1
lol@hyl:~/work/linux_study/Shared_memory/shm_fun$ ./p2
hello, world!

进程2顺利输出hello, world!

注意事项

(1)共享内存操作不规范导致冲突

当共享内存使用不规范,例如发生(1)大小不匹配、(2)未调用shmctl(ID, IPC_RMID, NULL)释放内存等情况时,系统会出现内存报错。 此时程序无法再次运行!即使关闭编译器后再次打开,仍然无法运行,因此共享内存仍然在系统内。
应对这种情况,需要在命令行输入

ipcs -m

之后终端会显示:


------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000001 6          hyl        666        20         0    

在这里我们可以看到我们申请的键值为1的ID号为6的共享内存,大小为20个字节,正是它的存在让我们无法再次以键值1申请共享内存,我们需要手动释放这块内存。

在命令行输入

ipcrm -m 6

最后的数字是共享内存的ID,删除后我们就可以再次运行程序了,要记得操作规范,及时在程序中释放哦!

共享内存的进程间安全问题

申请共享内存后,当两个进程想要同时向内存中写入数据会发生什么?
这个问题是一个很复杂的问题,涉及到进程间的安全性问题,学名叫进程间竞态竞争。我们将在信号量的学习中解决它,这里不过多赘述。
(我们展示的程序逻辑很简单,而且有先后运行顺序,不需要担心出现进程间冲突的问题)

小结

这节课我们学习了进程间通信的最高效手段——共享内存。
主要知识点:
(1)共享内存的四个接口函数:shmget、shmat,shmdt、shmctl
(2)共享内存的操作注意事项:大小一致,即使回收
(3)命令行中查看共享内存的指令(ipcs -m)与命令行中删除共享内存的指令(ipcrm -m shmid)

下一节我们将学习:消息队列

结束语

进程君的儿子在领悟到共享内存后,在修真界名声大振,隐隐有赶超其父亲的趋势。被人尊称为:进程公。(青出于蓝胜于蓝)

番外:什么!共享内存的另一种申请方式?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2334690.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

信息安全管理与评估2021年国赛正式卷答案截图以及十套国赛卷

2021年全国职业院校技能大赛高职组 “信息安全管理与评估”赛项 任务书1 赛项时间 共计X小时。 赛项信息 赛项内容 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 第一阶段 平台搭建与安全设备配置防护 任务1 网络平台搭建 任务2 网络安全设备配置与防护 第二…

高并发秒杀系统设计:关键技术解析与典型陷阱规避

电商、在线票务等众多互联网业务场景中&#xff0c;高并发秒杀活动屡见不鲜。这类活动往往在短时间内会涌入海量的用户请求&#xff0c;对系统架构的性能、稳定性和可用性提出了极高的挑战。曾经&#xff0c;高并发秒杀架构设计让许多开发者望而生畏&#xff0c;然而&#xff0…

微信小程序实战案例 - 餐馆点餐系统 阶段 2 – 购物车

阶段 2 – 购物车&#xff08;超详细版&#xff09; 目标 把“加入购物车”做成 全局状态&#xff0c;任何页面都能读写在本地 持久化&#xff08;关闭小程序后购物车仍在&#xff09;新建 购物车页&#xff1a;数量增减、总价实时计算、去结算入口打 Git Tag v2.0‑cart 1. …

sql 向Java的映射

优化建议&#xff0c;可以在SQL中控制它的类型 在 MyBatis 中&#xff0c;如果返回值类型设置为 java.util.Map&#xff0c;默认情况下可以返回 多行多列的数据

Visual Studio未能加载相应的Package包弹窗报错

环境介绍&#xff1a; visulal studio 2019 问题描述&#xff1a; 起因&#xff1a;安装vs扩展插件后&#xff0c;重新打开Visual Studio&#xff0c;报了一些列如下的弹窗错误&#xff0c;即使选择不继续显示该错误&#xff0c;再次打开后任然报错&#xff1b; 解决思路&am…

【HD-RK3576-PI】Docker搭建与使用

硬件&#xff1a;HD-RK3576-PI 软件&#xff1a;Linux6.1Ubuntu22.04 1.Docker 简介 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言开发&#xff0c;遵循 Apache 2.0 协议。它可以让开发者将应用程序及其依赖项打包到一个轻量级、可移植的容器中&#xff0c;并在任…

【websocket】使用案例( ​JSR 356 标准)

目录 一、JSR 356方式&#xff1a;简单示例 1、引入依赖 2、注册端点扫描器 3、编写通过注解处理生命周期和消息 4、细节解读 5、总结 二、聊天室案例 方案流程 1、引入依赖 2、注册端点扫描器 3、编写一个配置类&#xff0c;读取httpsession 4、编写通过注解处理生…

IS-IS中特殊字段——OL过载

文章目录 OL 过载位 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Datacom专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年04月13日20点12分 OL 过载位 路由过载 使用 IS-IS 的过载标记来标识过载状态 对设备设置过载标记后&#xff…

【时频谱分析】快速谱峭度

算法配置页面&#xff0c;也可以一键导出结果数据 报表自定义绘制 获取和下载【PHM学习软件PHM源码】的方式 获取方式&#xff1a;Docshttps://jcn362s9p4t8.feishu.cn/wiki/A0NXwPxY3ie1cGkOy08cru6vnvc

Spring Boot 支持的内嵌服务器(Tomcat、Jetty、Undertow、Netty(用于 WebFlux 响应式应用))详解

Spring Boot 支持的内嵌服务器详解 1. 支持的内嵌服务器 Spring Boot 默认支持以下内嵌服务器&#xff1a; Tomcat&#xff08;默认&#xff09;JettyUndertowNetty&#xff08;用于 WebFlux 响应式应用&#xff09; 2. 各服务器使用示例 (1) Tomcat&#xff08;默认&#xf…

微软Exchange管理中心全球范围宕机

微软已确认Exchange管理中心&#xff08;Exchange Admin Center&#xff0c;EAC&#xff09;发生全球性服务中断&#xff0c;导致管理员无法访问关键管理工具。该故障被标记为关键服务事件&#xff08;编号EX1051697&#xff09;&#xff0c;对依赖Exchange Online的企业造成广…

基于Qt的串口通信工具

程序介绍 该程序是一个基于Qt的串口通信工具&#xff0c;专用于ESP8266 WiFi模块的AT指令配置与调试。主要功能包括&#xff1a; 1. 核心功能 串口通信&#xff1a;支持串口开关、参数配置&#xff08;波特率、数据位、停止位、校验位&#xff09;及数据收发。 AT指令操作&a…

html简易实现推箱子小游戏原理(易上手)

实现效果 使用方向键移动&#xff0c;将橙色箱子推到绿色目标区域&#xff08;黑色块为墙&#xff0c;白色块为可通过区域&#xff0c;蓝球为小人&#xff09; 实现过程 <!DOCTYPE html> <html> <head><title>推箱子小游戏</title><style&g…

字符串与栈和队列-算法小结

字符串 双指针 反转字符串(双指针) 力扣题目链接 void reverseString(vector<char>& s) {for (int i 0, j s.size() - 1; i < s.size()/2; i, j--) {swap(s[i],s[j]);} }反转字符串II 力扣题目链接 遍历字符串的过程中&#xff0c;只要让 i (2 * k)&#…

类似东郊到家的上门按摩预约服务系统小程序APP源码全开源

&#x1f525; 为什么上门按摩正在席卷全国&#xff1f; 万亿蓝海市场爆发 2024年中国按摩市场规模突破8000亿&#xff0c;上门服务增速达65% 90后成消费主力&#xff0c;**72%**白领每月至少使用1次上门按摩&#xff08;数据来源&#xff1a;艾媒咨询&#xff09; 传统痛点…

Python | 在Pandas中按照中值对箱形图排序

箱形图是可视化数据分布的强大工具&#xff0c;因为它们提供了对数据集内的散布、四分位数和离群值的洞察。然而&#xff0c;当处理多个组或类别时&#xff0c;通过特定的测量&#xff08;如中位数&#xff09;对箱形图进行排序可以提高清晰度并有助于揭示模式。在本文中&#…

游戏引擎学习第215天

总结并为今天做铺垫 今天的工作内容是解决调试系统中的一个小问题。昨天我们已经完成了大部分的调试系统工作&#xff0c;但还有一个小部分没有完全处理&#xff0c;那就是关于如何层次化组织数据的问题。我们遇到的一个问题是&#xff0c;演示代码中仍有一个尚未解决的部分&a…

【Redis】redis事物与管道

Redis 事务&#xff08;Transaction&#xff09; 事务概念 事务&#xff1a;是一组操作的集合&#xff0c;是不可分割的工作单元。Redis 事务特点&#xff1a; 一个事务可以一次执行多个命令。所有命令都被顺序化&#xff0c;形成一个队列。所有命令在执行 EXEC 时一次性、顺…

Django信号使用完全指南示例

推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 **引言:****先决条件:****目录:****1. 什么是Django信号?****2:设置你的Django项目****2.1. 安装Django**2.2. 创建一个Django项…

vulkanscenegraph显示倾斜模型(5.9)-vsg中vulkan资源的编译

前言 上一章深入剖析了GPU资源内存及其管理&#xff0c;vsg中为了提高设备内存的利用率&#xff0c;同时减少内存(GPU)碎片&#xff0c;采用GPU资源内存池机制(vsg::MemoryBufferPools)管理逻辑缓存(VkBuffer)与物理内存(VkDeviceMemory)。本章将深入vsg中vulkan资源的编译(包含…