【Linux】进程间通信 ----- 共享内存(IPC资源)

system v 共享内存

每个进程都是独立的,当进程运行起来时,都有一个PCB,一个虚拟地址空间,一个页表,一个对应的物理内存,页表将每一个进程的PCB映射到物理内存的不同区域,保证了它们的独立性。但是如果两个页表都分别把进程虚拟地址空间的一些内容映射到物理内存的同一块区域,那么这样就实现了两个进程看到同一份资源了,而这一块公共的区域就叫做共享内存!如图所示:

因为可以减少进程间数据拷贝的次数,所以共享内存区是速度最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据

但与此同时,共享内存是直接暴露给用户的,所以没办法进行保护,则意味着不提供任何的互斥与同步机制,必须由用户自己来提供。因为它是system v 版本的IPC资源,所以生命周期随内核,也就是说你进程退出时,并不会删掉这一块共享内存。

 

共享内存的控制-----创建、挂接,脱离、删除

对于共享内存,我们能做的无非就只有四个动作,创建、挂接、脱离、删除。其中前两个可归类为创建,后两个归类为删除。那么具体的实现是要用到下面四个函数:

shmget函数:创建共享内存

共享内存的创建是以页为基本单位的

功能:用来创建共享内存 

#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key,size_t size,int shmflg);

参数
     key:这个共享内存段名字(保证两个进程看到的是同一块共享内存)key值是多少不关心,用如下方法创建key。

#include <sys/types.h>
#incldue <sys/ipc.h>

key_t ftok(const char *pathname,int proj_id);

     size:共享内存大小
     shmflg:

            IPC_CREAR:如果系统没有这个共享内存,则创建之;如果系统中已存在,使用系统的并返回。  

            IPC_CREAR,IPC_EXCL(两个一起使用):如果系统没有这个共享内存,则自己创建;如果系统有,则出错返回。

扫描二维码关注公众号,回复: 5024350 查看本文章

返回值:

      成功返回一个非负整数,即该共享内存段的标识码;失败返回-1(注意:这里的返回值标识码和key值是不同的,key值是给操作系统用的,为了标识唯一一块内存,从而保证两个进程看到的是同一块地址空间,但是这个返回值标识码是给用户用的。)

shmat函数:建立映射关系(挂接)

#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid:共享内存标识码
shmaddr :指定连接的地址 (虚拟地址,一般设置为NULL,让操作系统决定)
shmflg:它的两个可能取值为SHM_RND和SHM_RDONLY (一般设置为0)
返回值:返回一个指针,指向共享内存的而第一个节;失败返回-1

shmdt:取消映射关系(脱离)

#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);

shmaddr:要去掉连接的地址,由shmat返回的指针
返回值:成功返回0,不成功返回-1
(注意:这里只是把共享内存段和当前进程脱离,也就是去掉映射,不等于把共享内存删除。)

shmctl函数:控制共享内存(删除)----- 谁创建谁删除

#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmid:由shmget返回的标识码
cmd:要采取的动作

      IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值
      IPC_SET:在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值
      IPC_RMID:删除共享内存段

buf:指向一个保存着共享内存的模式状态和访问权限的数据结构(一般设置为NULL)

返回值:成功返回0,失败返回-1

除了函数之外,还有命令也可以查看和删除共享内存:

ipcs -m 查看共享内存相关信息
ipcrm -m (shmid)删除shmid标识号的共享内存

对于stmctl函数要多说一句:我们通过一些系统调用接口,传递特定的参数,是可以把一些属性信息从操作系统内部拿向用户层的,比如进程状态、进程pid、进程优先级等等;当然也有可能要设置一些属性,需要把一些属性设置到我们的操作系统中去,比如进程状态、进程优先级等等。这里的shmctl是对共享内存进行控制的,因此除了能够删除共享内存,当然也可以对共享内存的属性进行设置,但是一个共享内存不会只有一个属性,因此就有了shmid_ds这个结构体,里面存放了共享内存的大小,挂接数,key,mode,创建者,所属组等,可以让用户访问到共享内存的相关属性,因此shmid_ds这个结构体在操作系统底层肯定会有一个结构体与之对应,只不过shmid_ds这个结构体相当于一个容器要么把数据拿出来,要么把数据设置下去。(类似于waitpid里面的status参数,status参数也是相当于一个容器,把进程退出时的退出信息拿出来)。

 

代码实例

server.c

client.c

运行结果:现象与代码中实现的一致。

 

猜你喜欢

转载自blog.csdn.net/Miss_Monster/article/details/86564221