Linux:进程间通信之共享内存(IPC资源)

进程间通信----共享内存篇

system V共享内存

进程的运行具有独立性,每个进程都有独立的PCB、独立的地址空间、独立的页表,每个进程的页表将该进程的虚拟地址空间映射到了物理内存不同的数据区,因此进程之间是相互独立的,但是如果我们此时通过页表让两个进程的虚拟地址空间上的某一块区域通过自己的页表映射到物理内存的同一块内存区域上,那么两个进程就看到了同一块内存区域,那么A进程对这块内存的操作B进程就可以看到,反之,B进程对这块内存的操作A进程也可以看到,因此这一块AB进程都可以看到的内存区域我们称为共享内存。

通过图片深入理解:
在这里插入图片描述
共享内存区是最快的IPC形式,因为它可以减少了用户到内核之间数据拷贝的次数。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。但是有利就有弊,共享内存不提供任何的同步和互斥机制,只能由用户来提供。

当进程退出时,共享内存还在。所以system V版 IPC(共享内存)它的生命周期随内核。只要你这个程序不指定把共享内存删掉,那么这个共享内存就会一只存在。

共享内存的创建,挂接和删除

简单的说,要创建共享内存要有两步,第一步要有一块内存,第二步建立映射关系。那么要删除共享内存也要有两步,第一步取消映射关系,第二步释放这块内存。

那么具体怎么做我们得先认识这四个函数:

shmget创建共享内存

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

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);

key_t key:这个共享内存段名字(给系统用的,确保不同的进程能看到同一块内存)
size_t size:表示要创建共享内存的大小
int shmflg

IPC_CERAT:单独使用时,如果有共享内存,打开并返回,如果没有共享内存就创建一个
IPC_CERAT,IPC_EXCL:两个一起使用时,如果有共享内存就错误返回,如果没有共享内存就创建一个

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

基于shmget函数,我们知道有一个key值可以让系统知道我们的两个进程看到的是同一块内存,那么怎么创建key值呢?

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

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

key值只是为了标识一块唯一的内存空间,具体它是多少我们不用关心。

shmat建立映射(挂接)
#include <sys/types.h>
#include <sys/shm.h>

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

int shmid:共享内存标识码
const void shmaddr :指定连接的地址 (一般设置为NULL)
int shmflg:它的两个可能取值为SHM_RND和SHM_RDONLY (一般设置为0)
返回值:返回一个指针,指向共享内存的而第一个节

shmdt取消映射(去挂接)
#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);

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

shmctl对共享内存的控制(可以完成删除操作)
#include <sys/ipc.h>
#include <sys/shm.h>

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

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

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

struct shmid_ds buf:指向一个保存着共享内存的模式状态和访问权限的数据结构(一般设置为NULL)
返回值:成功返回0,失败返回-1

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

基于这四个函数我们还要了解共享内存的查看和删除的命令
ipcs -m 查看共享内存相关信息
ipcrm -m (shmid)删除shmid标识号的共享内存

示例代码

server.c
在这里插入图片描述
client.c
在这里插入图片描述
运行结果
通过运行结果我们知道至此完成了进程间的通信,同时我们也发现,当client休息不写的时候,server端读也依然读出了数据,因此我们同时也证明了共享内存没有同步和互斥机制。
在这里插入图片描述

文中代码
server.c

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/ipc.h>
  4 #include <sys/shm.h>
  5 
  6 #define PN "/tmp"
  7 #define PJ 0x5555
  8 int main()
  9 {
 10     key_t k=ftok(PN,PJ);
 11     if(k<0){
 12         printf("ftok error!\n");
 13         return 1;
 14     }
 15     int shmid=shmget(k,4096,IPC_CREAT | 0666);
 16     if(shmid<0){
 17         printf("shmid error!\n");
 18         return 2;
 19     }
 20     printf("shmid is:%d\n",shmid);
 21     char *buf=(char*)shmat(shmid,NULL,0);
 22     while(1){
 23         sleep(1);
 24         printf("%s\n",buf);
 25     }
 26     shmdt(buf);
 27     shmctl(shmid,IPC_RMID,NULL);
 28     return 0;
 29 }

client.c

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/ipc.h>
  4 #include <sys/shm.h>
  5 
  6 #define PN "/tmp"
  7 #define PJ 0x5555
  8 int main()
  9 {
 10     key_t k=ftok(PN,PJ);
 11     if(k<0){
 12         printf("ftok error!\n");
 13         return 1;
 14     }
 15     int shmid=shmget(k,4096,IPC_CREAT);
 16     if(shmid<0){
 17         printf("shmid error!\n");
 18         return 2;
 19     }
 20     printf("shmid is:%d\n",shmid);
 21     char *buf=(char*)shmat(shmid,NULL,0);
 22     char x='A';
 23     while(x<='Z'){
 24         sleep(5);
 25         buf[x-'A']=x;
 26         x++;
 27         buf[x-'A']=0;
 28     }
 29     shmdt(buf);
 30     return 0;
 31 }

猜你喜欢

转载自blog.csdn.net/ETalien_/article/details/86419043