一. 共享内存介绍
System V共享内存指的是把所有共享数据放在共享内存区域(IPC shared memory region),任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面。系统调用mmap()通过映射一个普通文件实现共享内存。系统V则是通过映射shm文件系统中的文件实现进程间的共享内存通信。也就是说,每个共享内存区域对应shm文件系统的一个文件。
二、System V共享内存API
对于系统V共享内存,主要有以下几个API:shmget()、shmat()、shmdt()及shmctl()。
#include <sys/ipc.h>
#include <sys/shm.h>
shmget()用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域。
shmat()把共享内存区域映射到调用进程的地址空间中去,这样,进程就可以方便地对共享区域进行访问操作。
shmdt()调用用来解除进程对共享内存区域的映射。
shmctl实现对共享内存区域的控制操作。
注:shmget的内部实现包含了许多重要的系统V共享内存机制;shmat在把共享内存区域映射到进程空间时,并不真正改变进程的页表。当进程第一次访问内存映射区域访问时,会因为没有物理页表的分配而导致一个缺页异常,然后内核再根据相应的存储管理机制为共享内存映射区域分配相应的页表。
三. System V共享内存范例
范例1
两个进程, 进程A创建一块共享内存, 写下Hello, World然后退出. 进程B根据key得到进程A创建的共享内存, 然后读取
共享内存中的数据. 并打印出来. 示意图如下:
进程A的代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <error.h>
#define SHM_SIZE 4096
#define SHM_MODE (SHM_R | SHM_W | IPC_CREAT) /* user read/write */
#define SHM_KEY 0x44 //key的生成可使用ftok(),可详细查询用法
int main(void)
{
int shmid;
char *shmptr;
if ( (shmid = shmget(SHM_KEY, SHM_SIZE, SHM_MODE)) < 0)
perror("shmget error");
if ( (shmptr = shmat(shmid, 0, 0)) == (void *)-1)
perror("shmat error");
/* 往共享内存写数据 */
sprintf(shmptr, "%s", "hello, world");
exit(0);
}
进程B的代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <error.h>
#define SHM_SIZE 4096
#define SHM_MODE (SHM_R | SHM_W | IPC_CREAT) /* user read/write */
int main(void)
{
int shmid;
char *shmptr;
if ( (shmid = shmget(SHM_KEY, SHM_SIZE, SHM_MODE)) < 0)
perror("shmget error");
if ( (shmptr = shmat(shmid, 0, 0)) == (void *)-1)
perror("shmat error");
/* 从共享内存读数据 */
printf("%s\n", shmptr);
if(shmctl(shmid, IPC_RMID, 0) < 0)
perror("shmctl error");
exit(0);
}
总结:
1、系统V共享内存中的数据,从来不写入到实际磁盘文件中去;而通过mmap()映射普通文件实现的共享内存通信可以指定何时将数据写入磁盘文件中。 注:系统V共享内存机制实际是通过shm文件系统中的文件实现的,shm文件系统的安装点在交换分区上,系统重新引导后,所有的内容都丢失。
2、系统V共享内存是随内核持续的,即使所有访问共享内存的进程都已经正常终止,共享内存区仍然存在(除非显式删除共享内存),在内核重新引导之前,对该共享内存区域的任何改写操作都将一直保留。
3、通过调用mmap()映射普通文件进行进程间通信时,一定要注意考虑进程何时终止对通信的影响。而通过系统V共享内存实现通信的进程则不然。