linux之进程通信——共享内存

Posted 努力学习的少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux之进程通信——共享内存相关的知识,希望对你有一定的参考价值。

目录

🌳.共享内存的机制

🌳. 创建共享内存

🍎. shmget函数

🍎.ftok函数

🍎. shmctl函数 

 🍎. shmat函数

🍎. shmdt函数

🍎. 代码实例

🌳.区分key值和shmid

🍎. 管道的方式进行通信

往期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之进程间通信】——管道

【linux】——动静态库

【linux】——基本的文件操作 

【linux】——文件系统

以上是关于linux之进程通信——共享内存的主要内容,如果未能解决你的问题,请参考以下文章

linux进程间通信之System V共享内存详解及代码示例

linux之进程通信——共享内存

Linux之进程间通信

Linux之进程间通信

linux之进程通信——共享内存

linux进程间通信之Posix共享内存用法详解及代码举例