进程间通信(IPC)之共享内存

Posted Xiao__Tian__

tags:

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

★IPC方法包括管道(PIPE)、消息队列(Message_Queue)、旗语、共用内存(ShareMemory)以及套接字

(Socket)。进程间通信主要包括了管道、系统IPC(包括了消息队列、信号以及共享存储)、套接字(Socket)。

此文将叙述共享内存的相关内容。


在此之前先来看看关于进程的内存映像的相关内容。

一、进程的内存映像(区别于可执行程序文件):

指的是内核在内存中如何存放可执行程序文件。两者的区别表现在三个方面:①可执行程序是位于硬盘上的,而内存映像位

于内存上; ②可执行程序没有堆栈,因为只有当程序被加载到内存上的时候才会分配相应的堆栈;③可执行程序是静态的,因为它

还没运行,但是内存映像是动态的,数据是随着运行过程改变的。

Linux下C程序生成进程的内存映像主要由四个步骤组成:预编译、编译、汇编、链接。编译器gcc经过预编译、编译、汇编

3个步骤将源程序文件转换成目标文件。如果程序有多个目标文件或程序中使用了库函数,则编译器还需要将所有目标文件及所需的

库文件链接起来,最后生成可执行程序。当程序执行时,操作系统将可执行程序复制到内存中。其布局如下图:






注:其中正文所在的区域为只读代码和只读数据区域,也就是通常所说的代码段,用来存放程序的执行代码,包括了

只读的常数变量,例如:字符串常量等。而未初始化的数据区域称为BSS(Block Started by Symbol)段,用来存

放未初始化的全局变量,属于静态内存分配的一部分。初始化的数据区域称为数据段,用来存放已初始化的全局变

量,也属于静态内存分配的一部分,所以一般习惯地将BSS段和数据段统称为数据段。







二、不同进程读取同一数据块时的地址分配






注:图中的地址空间为虚拟空间地址,可以看到不同的进程PCB1和PCB2读取相同的地址空间处时,通过页表和也表

描述符mmu分别指向了不同的物理地址,所以尽管表面上看起来两个进程访问的同一地址,其实际映射得到的物理

地址却并非如此。





三、共享内存

共享内存是被多个进程共享的部分物理内存。一个进程向共享内存区域一旦写入了数据,共享这个内存区域

的所有进程就可以直接看到其中的内容。享内存允许两个不相关的进程访问同一个逻辑内存,是两个正在运行的进

程之间共享和传递数据的一种非常有效的方式。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程

都可以访问共享内存中的地址,也就是说一旦进程改动共享内存中的数据时,会影响到访问该区域的其他进程。



★关于共享内存函数的声明,在头文件sys/shm.h中。






注:图中的红框部分表明了共享内存(shm)与进程间通信的类属关系,同样拥有ipc perm的结构体。白框则表明了共

享内存的四个常用操作函数。




1.shmat函数:

第一次创建完共享内存时,不能被任何进程访问,shmat函数的作用就是用来启动对该共享内存的访问,并把共

享内存连接到当前进程的地址空间。其原型如下图




注:可以看到,该函数中有三个形参,shm_id是由shmget函数返回的共享内存标识;shm_addr指定共享内存连接

到当前进程中的地址位置,一般为空,表示让系统来选择共享内存的地址;shm_flg是一组标志位,通常为0。其返

回值调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败则返回-1。





2.shmctl函数:

与信号量的semctl函数一样,用来控制共享内存,原型如下

   


注:shmctl函数中同样具有三个形参,shm_id是shmget函数返回的共享内存标识符;command是要采取的操

作,可取三个值 :①IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关

联值覆盖shmid_ds的值;②IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中

给出的值;③IPC_RMID:删除共享内存段。buf是一个结构指针,它指向共享内存模式和访问权限的结构。





3.shmdt函数:

用于将共享内存从当前进程中分离。(注:将共享内存分离并不是删除它,只是使该共享内存对当前进程不再

可用)。其原型见下图:




注:参数shmaddr是shmat函数返回的地址指针,其返回值调用成功时返回0,失败时返回-1。





4.shmget函数:

用于创建共享内存,其函数原型见下图:




注:该函数拥有三个形参,key与信号量的semget函数一样,程序需要提供一个参数key(非0整数),有效地为共

享内存段命名,shmget函数成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函

数,调用失败则返回-1;size以字节为单位指定需要共享的内存容量;shmflg是权限标志,它的作用与open函数的

mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做“或”操作。共享内

存的权限标志与文件的读写权限一样。



▲不相关的进程可以通过该函数的返回值访问同一共享内存,它代表程序可能要使用的某个资源,程序对所有共享内

存的访问都是间接的,程序先通过调用shmget函数并提供一个键,再由系统生成一个相应的共享内存标识符

(shmget函数的返回值),只有shmget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回

的信号量标识符。




★练习:创建两个进程,在A进程中创建一个共享内存,并向其写入数据,通过B进程从共享内存中读取数据。


1.shm_comm.h文件:




2.read_process.c文件:




3.write_process.c文件:






4Makefile自动化编译文件:





★运行结果:






★总结:

共享内存特点:

①进程间通信中速度最快的,且需要被挂起。原因:享内存区的文件中的数据内容可以直接由共享双方直接访问,没有数据拷贝时间消耗,所以速度很快。

②不提供任何的同步和互斥机制,须用户自主维护(可通过信号量及设置同步机制等手段)。

③接口较为简单。







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

进程间通信(IPC)之消息队列

进程间通信(IPC)之消息队列

进程间通信IPC之--共享内存

五十进程间通信——System V IPC 之共享内存

linux进程间的通信之 共享内存

深入详解Linux进程间通信之共享内存(Shared Memory)