共享内存是最快的IPC通信方式,在日常工作中经常使用,但是却一直没有区分使用的是哪种共享内存,今天把这块知识补充了一下。
父子进程共享内存区
首先考虑简单的共享内存场景,父子进程共享内存。
父子进程间通常不需要使用Posix共享内存或者System V共享内存,因为父进程通过fork调用派生出子进程,虽然父子进程拥有各自独立的共享内存区,但是由于fork会对内存映射文件进行特殊处理(虚拟内存),所以一般通过内存映射文件的方式在父子进程间共享内存区。
使用该方法有几个地方需要注意
- 父进程在调用mmap函数的使用需要指定MAP_SHARED标记。
- 父子进程读写共享内存需要使用某种方式同步
- 通常可以使用匿名内存映射的方式来简化父子进程共享内存区的使用。BSD提供了匿名内存映射标志MAP_ANON,SVR4提供/dev/zero设备可以用于匿名内存映射
Posix共享内存
在Posix标准中,共享内存区可以用于没有亲缘关系的进程之间,符合Posix标准的共享内存实现方式成为Posix共享内存。
Posix提供了两种在没有亲缘关系的进程之间使用共享内存区的方法
- 内存映射文件的方式
通过将磁盘上的文件映射到内存,也可以实现没有亲缘的进程之间的共享内存,实现方式和父子间共享内存类似。 - 共享内存区对象
由sh_open打开一个Posix共享内存区对象,返回的描述符再由mmap函数映射到当前进程的地址空间。传递给shm_open的名字随后由希望共享该内存区的任何其它进程使用。
操作共享内存区对象的方法
- shm_open,创建或打开共享内存区
- shm_unlink,从系统中删除共享内存区对象
- ftruncate,设置共享内存区对象的大小
- fstat,获取共享内存区对象的相关信息
System V共享内存
System V共享内存区和Posix共享内存区概念上相似,只是在调用接口上有所不同。
常用的函数调用有以下几个
- shmget,获取一个标识符
- shmat,把一个共享内存区attach到调用进程的地址空间
- 以IPC_STAT命令调用shmctl,获取一个已存在的共享内存的大小
- 以IPC_RMID命令带哦用shmctl,删除一个共享内存区对象
Posix和System V的共同点
两种共享内存区都是至少具有随内核的持续性,所创建的共享内存对象会一致存在,直到其所有引用都关闭并且该对象被显式删除
Posix 和 System V的差别
Posix共享内存区对象的大小在任何时刻可以通过ftruncate函数修改,而System V共享内存区的大小是在调用shmget创建时固定下来的
网友评论