共享内存原理及实现通信过程
共享内存的概念及创建过程
一. 共享内存的概念
共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。
进程通信的本质就是让两个进程看到同一个空间,所以共享内存就是在物理内存中申请一块空间,然后让通信的每个进程通过进程地址空间与页表完成从物理地址到进程地址空间的映射,然后就可以对该块空间进行修改与读取了。
二. 共享内存的创建过程
- 首先要申请共享内存,也就是在物理地址中开辟好共享内存空间,供进程间通信使用。而且我们知道物理地址中的共享内存可能会有很多个,那么肯定就要管理这些内存,所以要管理我们就要先描述再组织,所以出了创建共享内存之外,还要为共享内存创建描述共享内存的内核数据结构。
- 将共享内存挂接到地址空间,本质上就是给两个进程之间的共享内存和虚拟地址空间之间建立映射,之后就可以开始进程间的数据传输与修改了。
- 用完之后要去掉共享内存和进程地址空间之间的联系,本质上就是修改页表,取消共享内存和虚拟内存的映射关系。
- 释放共享内存,将内存归还给系统。
共享内存的使用函数
一. 创建共享内存函数shmget
首先我们来看该函数的参数分别为:
int shmget(key_t key , size_t size , int shmflag);
第一个参数key是用来标识共享内存的,可以保证共享内存本身的唯一性。那么我们就要得到这个key,这里就可以通过系统调用接口:key_t ftok(pathname , PROJ_ID);通过此函数就可以创建key值。如下图:

这样我们就可以通过shmget函数来创建共享内存了,如下图:

这里shmget的第二个参数表示要创建共享内存的大小的,而后面的IPC_CREAT表示我们要创建共享内存,这里的IPC_CREAT表示如果当前路径下不存在共享内存就创建一个新的共享内存,如果存在共享内存就直接使用该共享内存。后面的IPC_EXCL一般都和IPC_CREAT一起使用,两个标志位一起使用的时候就表示如果该路径下不存在共享内存就创建新的共享内存,如果存在共享内存就会报错,这样就可以保证我们永远使用的都是新创建的共享内存,这样就可以避免使用其他进程创建的共享内存而导致错误。后面的0644表示当前共享内存的权限。这样我们就可以通过ipcs -m命令看到我们创建的共享内存了,如下图:

二. 建立物理内存与进程地址空间之间的关联shmat函数
void *shmat(int shmid, const void *shmaddr, int shmflg);
通过该函数就可以在物理内存中创建的共享内存关联到内存地址空间中,这样就可以使用一个指针指向这块内存地址空间了,直接在进程地址空间中修改数据就可以了。
这里第一个参数就是上面我们创建的shmid,用来表示该块共享内存,第二个参数表示共享内存的地址,这里我们不需要管直接使用NULL让系统给我们分配就可以了,第三个表示标志位,使用0就可以了。如下图:

三. 将物理内存与进程地址空间之间取消关联shmdt函数
上面我们通过shmat函数建立了两者之间的关联,之后用一个指针指向这块空间,那么我们要想去关联的话直接把这个指针作为参数调用shmdt就可以了,如下图:

四. 释放在物理内存中创建的共享内存shmctl函数
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
该函数的第一个参数我们就不介绍了,第二个参数表示是一个系统宏,这里我们使用的是IPC_RMID,此标志位就是用来释放内存的,第三个参数我们直接使用NULL就可以了。如下图:

使用共享内存完成通信
这里实现的通信大致的步骤就是首先我们创建两个文件,用来表示两个进程,这里可以将两个文件分别取名为:server.c和client.c,之后在server.c中我们首先使用ftok函数创建一个证明共享内存唯一性的key,之后通过该key值和shmget函数创建一个shmid来标识共享内存,然后使用shmat函数将物理地址中开辟的共享内存和进程地址空间进行关联,之后我们让server.c读数据,然后通过shmdt函数取消关联和shmctl函数来删除共享内存。在client.c文件中我们也是按照上面的方式使用共享内存,之后我们往共享内存中写入数据,让server.c读,之后我们就完成了通过共享内存来实现进程间通信,具体代码如下图:
Server.c

Client.c

Comm.h


3211

被折叠的 条评论
为什么被折叠?



