目录

一.共享内存介绍

(一).什么是共享内存

(二).共享内存优点

(三).共享内存缺点

二.共享内存使用

(一).创建—shmget

①key

②size

③shmflg

④返回值

(二).连接—shmat

(三).分离—shmdt

(四).销毁—shmctl

(五).查看—ipcs

(六).删除—ipcrm

(七).读取与写入

三.共享内存与访问控制

(一).添加访问控制

(二).可能的陷阱


一.共享内存介绍

(一).什么是共享内存

共享内存本质上就是内存中的一块区域,用于进程间通信使用。该内存空间由操作系统分配与管理。与文件系统类似的是,操作系统在管理共享内存时,不仅仅有内存数据块,同时还会创建相应结构体来记录该共享内存属性,以便于管理。

因此,共享内存不只有一份,可以根据需求申请多个。

进程之间进行通信的时候,会获取 到共享内存的地址,写端进程写入数据,读端进程通过直接访问内存完成数据读取。

(二).共享内存优点

相比于管道而言,共享内存不仅能够用于非父子进程之间的通信,而且访问数据的速度也比管道要快。这得益于通信直接访问内存,而管道则需要先通过操作系统访问文件再获得内存数据。

(三).共享内存缺点

用于进程间通信时,共享内存本身不支持阻塞等待操作。这是因为当读端读取数据后,数据并不会在内存中清空。因此读端和写端可以同时访问内存空间,即全双工。因为共享内存本质是进程直接访问内存,无法主动停止读取,如果读端不加以限制,那么将持续读取数据。同理,写端也会持续写入数据。换句话说,共享内存本身没有访问控制。

二.共享内存使用

(一).创建—shmget

想要使用共享内存首先要建立共享内存。

①key

shmget会根据key值创建一个共享内存,因此当创建多个共享内存时,每一个key值要独一无二。

获得key值可以使用库函数ftok专门获取一个独一无二的key_t类型值。

参数pathname为路径,必须是真实存在且可以访问的路径。

参数proj_id是int类型数字,且必须传入非零值。

成功返回key_t值,失败返回-1。

ftok函数内部会根据路径和proj_id通过算法生成一个独一无二的key_t返回值。

多进程通信时,需要通信双方使用同一个key值,因此双方使用的ftok参数应该一致。

②size

该参数用于确定共享内存大小。

一般而言是4096的整数倍,因为内存的块的大小就是4KB即4096B。因此即便我们需要的空间大小不是块大小的整数倍,操作系统实际上也还是分配块的倍数个。但在使用时,那些超过size大小的多余分配空间不能访问

③shmflg

该参数用于确定共享内存属性。

使用上为:标志位 | 内存权限

标志位参数有两种:IPC_CREAT、IPC_EXCL

常用使用方式有两种:

方式 含义
shmget(..., IPC_CREAT | 权限) 创建失败不报错返回已有shmid
shmget(..., IPC_CREAT | IPC_EXCL | 权限) 创建失败报错返回-1

值得注意PC_EXCL无法单独使用。

通常情况下在多进程通信时,创建方使用IPC_CREAT | IPC_EXCL,接收方使用0即可。

④返回值

返回值为int类型,称为shmid。每一个共享内存都会有一个shmid,用于连接与分离时传递参数。

(二).连接—shmat

创建共享内存后还不能直接使用,需要找到内存地址后才能使用,即连接。

shmid即shmget返回值。

shmaddr用于确定将共享内存挂在进程虚拟地址哪个位置,一般填nullptr即可代表让内核自己确定位置。

shmflg用于确定挂接方式,一般填0

连接成功返回共享内存在进程中的起始地址,失败返回-1。

(三).分离—shmdt

当使用完毕后,需要分离挂接的共享内存。

shmaddr与shmat的相同,为共享内存在进程中地址位置,一般填nullptr。

分离成功返回0,失败返回-1。

(四).销毁—shmctl

该接口本身用于控制共享内存,可用于销毁。

shmid不再介绍,cmd传入IPC_RMID,buf传nullptr。

成功返回0,失败返回-1。

(五).查看—ipcs

该指令为系统指令。

使用时可以查看当前全部共享内存。

ipcs -m 

(六).删除—ipcrm

通过指定共享内存shmid,进行删除。

ipcrm -m [shmid]

(七).读取与写入

调用shmat后会返回一个地址,读端直接读取该地址数据,写端直接向该地址写入即可。

//读端, 将共享内存数据读取到文件,此处为显示器文件
char* p = (char*)shmat(...);
write(1, p, sizeof p);
//写端,将文件中数据写入共享内存,此处为键盘文件
char* p = (char*)shmat(...);
read(0, p, 4096);

三.共享内存与访问控制

(一).添加访问控制

通过博客第一部分我们知道,共享内存不支持访问控制,那么我们可不可以添加访问控制给共享内存呢——完全可以。

方式是借用命名管道的访问控制,即阻塞。 

首先我们有如下代码,该代码是读端一直读取写端数据,直到写端输入quit为止。

//写端
int main()
{key_t key = ftok(".", 131);int shmid = shmget(key, 4096, IPC_CREAT|0660);//获取shmidchar* p = (char*)shmat(shmid, nullptr, 0);//连接while(1){ssize_t s = read(0, p, 4096);//写入shmp[s - 1] = 0;assert(s > 0);(void)s;}shmdt(p);//分离return 0;
}
//读端
int main()
{key_t key = ftok(".", 131);int shmid = shmget(key, 4096, IPC_CREAT|IPC_EXCL|0660);//创建char* p = (char*)shmat(shmid, nullptr, 0);//连接while(1){assert(p != nullptr);if(strcmp(p, "quit") == 0)break;printf("%s\n", p);//读取shm中数据sleep(1);}shmdt(p);//分离shmctl(shmid, IPC_RMID, nullptr);//销毁return 0;
}

但是因为共享内存无法访问控制,读端会一直读取数据,即便我们添加sleep函数也不能从根本解决问题。

解决方式是,在读端和写端分别加上管道的读端和写端。因为我们知道管道读端在读取到来自写端的数据前会阻塞,因此,将管道读端放在共享内存读端之前,将管道写端放在共享内存写端之后。

这样一来,当shm写端写入数据后会触发管道写端写数据,当管道写端写入数据后,管道读端才会停止阻塞,进而执行shm读端。

图例如下:


代码如下:

//写端
int main()
{key_t key = ftok(".", 131);int shmid = shmget(key, 4096, IPC_CREAT|0660);//获取shmidchar* p = (char*)shmat(shmid, nullptr, 0);//连接int fd = open(..., O_WRONLY);//打开命名管道while(1){ssize_t s = read(0, p, 4096);//写入shmp[s - 1] = 0;assert(s > 0);(void)s;char i[4] = { 0 };write(fd, i, sizeof i);//写入管道}shmdt(p);//分离close(fd);return 0;
}
//读端
int main()
{int i = mkfifo(PATH_FIFO, 0660);//创建管道assert(i >= 0);key_t key = ftok(".", 131);int shmid = shmget(key, 4096, IPC_CREAT|IPC_EXCL|0660);//创建char* p = (char*)shmat(shmid, nullptr, 0);//连接shmint fd = open(..., O_RDONLY);//连接管道while(1){char buf[4];read(fd, buf, sizeof buf);//管道等待读取,阻塞assert(p != nullptr);if(strcmp(p, "quit") == 0)break;printf("%s\n", p);//读取shm中数据sleep(1);}shmdt(p);//分离shmctl(shmid, IPC_RMID, nullptr);//销毁close(fd);return 0;
}

(二).可能的陷阱

在添加访问控制时,会有一个可能的陷阱,就是命名管道可不可以在创建shm之前打开(open)呢?

不可以,因为打开管道要求读端和写端同时打开才能继续,否则就会阻塞。

如果阻塞的是写端还好,当读端创建完shm后写端创建失败返回shmid,但是如果阻塞的是读端,那么写端创建shm后,读端创建时因为加上IPC_EXCL的缘故,失败返回-1,之后shmat也失败返回nullptr,进而读端获取到的地址是空。

简单模块注意封装,复杂模块注意分层——未名


如有错误,敬请斧正

Linux——详解共享内存shared memory相关推荐

  1. linux shared,从 0 开始学习 Linux 系列之「22.共享内存 Shared Memory」

    共享内存 版权声明:本文为 cdeveloper 原创文章,可以随意转载,但必须在明确位置注明出处! 共享内存 Shared Memory 这次我们来学习在 Linux 中最快的一种 IPC 方式:共 ...

  2. ipcs命令详解——共享内存、消息队列、信号量定位利器【转】

    (转自:https://blog.csdn.net/dalongyes/article/details/50616162?utm_medium=distribute.pc_relevant.none- ...

  3. linux如何创建共享内存,linux实现共享内存同步的四种方法

    https://blog.csdn.net/sunxiaopengsun/article/details/79869115 本文主要对实现共享内存同步的四种方法进行了介绍. 共享内存是一种最为高效的进 ...

  4. 进程间通信之-共享内存Shared Memory--linux内核剖析(十一)

    共享内存 共享内存是进程间通信中最简单的方式之中的一个. 共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区. 共享内存同意两个或很多其他进程訪问同一块内存,就如同 malloc() 函数 ...

  5. linux ipc shmget 例子,Linux IPC之共享内存C 事例(示例代码)

    简介 共享内存(shared memory)是最简单的Linux进程间通信方式之一.使用共享内存,不同进程可以对同一块内存进行读写.由于所有进程对共享内存的访问就和访问自己的内存空间一样,而不需要进行 ...

  6. Linux进程间通信——使用共享内存

    下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式 ...

  7. 详解JVM内存管理与垃圾回收机制5 - Java中的4种引用类型

    在Java语言中,除了基础数据类型的变量以外,其他的都是引用类型,指向各种不同的对象.在前文我们也已经知道,Java中的引用可以是认为对指针的封装,这个指针中存储的值代表的是另外一块内存的起始地址(对 ...

  8. 嵌入式linux详解,嵌入式Linux详解

    嵌入式Linux详解 嵌入式培训就是嵌入式系统相关技术的培训.嵌入式系统说白了就是硬件和软件相结合,嵌入到整机里使整机实现智能化的一个系统.下面是小编整理的关于嵌入式Linux详解,希望大家认真了解! ...

  9. 【操作系统实验】Linux进程通信—共享内存通信、管道通信

    Linux进程通信-共享内存通信.管道通信 一.实验目的: 二.实验题目: 1. 试设计程序利用共享内存完成如下进程通信 1.shmget函数 2.shmat函数 3.shmdt函数 4.shmctl ...

最新文章

  1. 用自定义IHttpModule实现URL重写
  2. 个人作业——软件工程实践总结
  3. 推荐算法炼丹笔记:推荐系统采样评估指标及线上线下一致性问题
  4. linux 头文件汇总
  5. FFMPEG 图像拉伸缩放及数据格式转换
  6. JDK+SDK 环境变量记录
  7. android sdk build tools 版本,SDK Build Tools 版本说明
  8. ViewController的view的创建
  9. 人力资源管理(HR)专业书籍推荐
  10. JavaScript页面跳转并传参的常用方法
  11. linux windows凤凰,凤凰系统率先升级内核到Linux4.9,支持更多新硬件
  12. Windows 7 万能驱动下载 免费
  13. 【其实是空空荡荡的牵挂,没有结局的怀念】
  14. Activiti工作流之任务的运行/查询/完成
  15. Python自动化爬取天眼查数据
  16. 计算机上如何使用文件管理器,苹果iphone iFiles文件管理器使用图文教程
  17. 腾讯云-产品开通和密钥查看
  18. OS学习笔记-2(清华大学慕课)mooc实验介绍
  19. JDK 8 - computeIfAbsent,computeIfPresent,compute
  20. 基于ZooKeeper的分布式锁和队列

热门文章

  1. Android短视频开发中的sdk接入方案
  2. 计算机网络 概述重点(全)
  3. 【地图匹配(ST-matching)】GPS 轨迹数据预处理——T-Driver数据集【持续更新中】
  4. Html a标签的用法
  5. 成都理工大学计算机考研经历,09计算机考研的小小体会~
  6. NLP-D32-毕设答辩准备-《人类语言处理》03-04
  7. Galaxy Tab3 10.1如何开启被隐藏的开发者选项?
  8. Win 8预览版将上市 首批应用名单出炉
  9. web前端培训靠谱吗,收费怎么样?
  10. Linux系列6:bash学习