当前位置: 首页 > news >正文

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

前言

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

共享内存

进程间的通信手段分别有:管道,共享内存,消息队列,信号,信号量,套接字。今天我们将学习第二种方式,共享内存(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			# 这里面的-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)

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

结束语

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

番外:什么!共享内存的另一种申请方式?请移步linux多线(进)程编程——番外1:内存映射与mmap

相关文章:

  • 链表代码实现(C++)
  • C语言--常见的编程示例
  • 医药采购系统平台第5天01:药品目录导入功能的实现Oracle触发器的定义供货商药品目录模块的分析供货商目录表和供货商控制表的分析、数据模型设计和优化
  • Rasa 模拟实现超简易医生助手(适合初学练手)
  • Tkinter表格与列表框应用
  • 制作像素风《饥荒》类游戏的整体蓝图和流程
  • ubuntu 2404 安装 vcs 2018
  • Doris 安装部署、实际应用及优化实践:对比 ClickHouse 的深度解析
  • 从零搭建高可用Kafka集群与EFAK监控平台:全流程实战总结
  • Foxmail邮件客户端跨站脚本攻击漏洞(CNVD-2025-06036)技术分析
  • Go:基本数据
  • leetcode 139. Word Break
  • < 自用文 Project-30.6 Crawl4AI > 为AI模型优化的网络爬虫工具 帮助收集和处理网络数据的工具
  • Java中的数组
  • 苍穹外卖Day-5
  • c# 新建不重名的唯一文件夹
  • STM32 HAL库时钟系统详解
  • AndroidTV 当贝播放器-v1.5.2-官方简洁无广告版
  • SAP-ABAP:BAPI_ACC_DOCUMENT_POST 详解(总账、应收账款、应付账款等业务场景的自动化集成)
  • Android 存储路径
  • 暗蓝评《性别打结》丨拆解性别之结需要几步?
  • 湖南华容县通报“大垱湖水质受污染”,爆料者:现场已在灌清水
  • 特朗普声称中方领导人打了电话,外交部:近期中美元首没有通话
  • 国家发改委:建立实施育儿补贴制度
  • 影子调查丨起底“三无”拖拉机产销链:出口掩内销,监管如虚设
  • 涨价应对关税变化是短期之策,跨境电商塑造新品牌开辟“新蓝海”