linux之进程通信——共享内存
Posted 努力学习的少年
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux之进程通信——共享内存相关的知识,希望对你有一定的参考价值。
目录
🌳.共享内存的机制
让进程拿出一块虚拟地址空间来,映射到相同的内存中,使不同的进程都能看到同一块空间,
这样就能实现不同的进程进行通信。
🌳. 创建共享内存
🍎. shmget函数
int shmget(key_t key, size_t size, int shmflg);功能:创建一个共享内存key:在内核中标识共享内存的标识符,需要用ftok函数来创建。size:创建共享内存的大小shmflg:参数选项,如下:
- IPC_CREAT:如果该key值有对应的共享内存,则返回该共享内存的标识符,如果不存在,则创建共享内存,并返回该共享内存的标识符,单纯一个IPC_CREAT的参数是不能判断shmget是否创建全新的共享内存。
- IPC_CREAT|IPC_EXCL:如果该key值有对应的共享内存不存在,则会出错返回,不然则创建新的共享内存,可以确保创建的共享内存是全新的。
返回值:成功返回一个非负整数,即共享内存的标识符shmid,是在进程层面上进行标识的。失败返回-1.
🍎.ftok函数
#include <sys/types.h>
#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);
功能:将pathname和proj_id根据某种算法生成一个key值,用来区分内核中的共享内存和消息队列,信号量。
pathname:指定一个已存在的文件,且这个文件是可以访问的
proj_id: 可以根据自己的约定,随意设置。这个数字,有的称之为project ID; 在UNIX系统上,它的取值是1到255;
返回值:返回一个key值
🍎. shmctl函数
功能:用于控制共享内存原型int shmctl(int shmid, int cmd, struct shmid_ds *buf);参数shmid :共享内存的标识符, 由 shmget 返回的共享内存标识符cmd : 将要采取的动作
- IPC_RMID:删除共享内存
buf : 指向一个保存着共享内存的模式状态和访问权限的数据结构返回值 :成功返回 0 ;失败返回 -1
🍎. shmat函数
功能:将共享内存段映射到进程地址空间原型void *shmat(int shmid, const void *shmaddr, int shmflg);、参数:shmid :共享内存标识符,即shmget返回的值。shamaddr :指定连接地址。如果传NULL,则系统会自动在该进程的虚拟内存选一个合适的地址。shmflg :
- 0:读写方式
- SHM_RDONLY:为只读模式。
返回值:成功返回的是共享内存映射该进程虚拟内存上的起始地址,失败返回-1.
🍎. shmdt函数
功能:取消共享内存与进程虚拟内存的映射
原型:int shmdt(const void *shmaddr);
参数:
shmaddr:映射在共享内存的虚拟地址,即shmat的返回值。
返回值:成功返回0,失败返回-1.
先利用ftok生成一个key值,然后利用这个key值,创建出一个共享内存,使进程A和进程B都能看到这块共享内存,然后将这块共享内存与进程A和进程B的虚拟内存进行映射,通信完毕的时候,取消共享内存和进程A和进程B的虚拟地址之间的映射,然后再将共享内存给删掉即可。
第二步:将共享内存映射到进程的虚拟地址上
结束通信时:
第一步:取消映射
第二步:删除共享内存
🍎. 代码实例
makefile文件
comm.h文件
server.c
1.如果创建的共享内存没有指定权限的话,那么创建出来的共享内存是没有任何权限,是无法与我们进程的虚拟地址建立映射关系。
2.如果共享内存已存在,则IPC_CREAT|IPC_EXCL会直报错退出。
3.同一个pathname,proj_id生成的key值是一样的,接下来client.c文件生成的key是一样的,所以它们找到的是同一个共享内存。
client.c
运行结果:
当我们创建共享内存后,我们应该怎样查看内核中的共享内存;
ipcs -m 查看系统中的共享内存
ipcrm -m shmid 删除某个共享内存
🌳.区分key值和shmid
key值和shmid它们都是共享内存的标识符,那么我们怎么理解这两个数字呢?
key值是在内核中标识共享内存的唯一性的方式,也就是说操作系统要找到某个共享内存,就通过key值进行查找。
shmid值是进程内部标识共享内存的唯一性的方式,进程想要找共享内存,就通过shmid值去查找。
总结:shmid值是对key值进行了封装,它是在进程内部进行区分的,如果进程想要去内核中找共享内存,就需要通过shmid值找到key值,然后通过key值找到我们的共享内存。
🍎. 共享内存的方式进行通信
文件1通过进程虚拟内存和共享内存的映射关系,可以直接往共享内存上写入数据,文件2可以将共享内存的数据直接写到文件2上。
🍎. 管道的方式进行通信
如图所示:
文件1是不能将数据直接写道我们的管道上,需要先将数据直接写到进程A上,然后再将数据写入到管道,进程也不能直接将数据写入到文件2,提取需要在管道中提取数据,然后才可以写入到文件2.
因此,进程往共享内存中写入数据,另一个进程可以立马可以看到,所以共享内存的通信效率是非常快的。
往期linux文章
以上是关于linux之进程通信——共享内存的主要内容,如果未能解决你的问题,请参考以下文章