进程间通信机制详解(4)——共享内存

共享内存

共享内存就是允许两个或多个进程共享一定的存储区,共享内存映射能够最大限度的降低内核空间和用户空间之间的数据拷贝,当内核空间和用户空间存在大量数据交互时,这些进程的数据传输不再涉及内核,从而大大提高系统的性能,是最快的IPC形式。
当一个程序加载进内存后,它被分成叫作页的块。每个进程都有属于自己的进程控制块(PCB)和地址空间(Addr Space),并且都有一个与之对应的页表,负责将进程的虚拟地址与物理地址进行映射。当一个程序想和另外一个程序通信的时候,两个不同的虚拟地址通过页表映射到物理空间的同一区域,它们所指向的这块区域即共享内存。
进程间通信机制详解(4)——共享内存_第1张图片
现阶段广泛应用于多媒体、Graphics领域的共享内存方式,某种意义上不再强调映射到进程虚拟地址空间(映射的目的是能够让CPU访问),而更强调以某种“句柄”的形式,实现跨进程访问内存。
进程间通信机制详解(4)——共享内存_第2张图片
对于一个共享内存,实现采用的是引用计数的原理,当进程脱离共享存储区后,计数器减一,挂接成功时,计数器加一,只有当计数器变为零时,才能被删除。当进程终止时,它所附加的共享存储区都会自动脱离。

共享内存的方式

1.基于传统SYS V的共享内存;
2.基于POSIX mmap文件映射实现共享内存;
3.通过memfd_create()和fd跨进程共享实现共享内存;
4.多媒体、图形领域广泛使用的基于dma-buf的共享内存。

SYS V

ipcs:查看系统中的共享存储段
ipcrm:删除系统中的共享存储段 
shmget ( ):创建共享内存 
shmat ( ):挂接共享内存, 创建共享存储段之后,将进程连接到它的地址空间 
shmdt ( ):去关联共享内存,当一个进程不需要共享内存的时候,就需要去关联。该函数并不删除所指定的共享内存区,而是将之前用shmat函数连接好的共享内存区脱离目前的进程。 
shmctl ( ):销毁共享内存

POSIX mmap

Posix提供了两种在无亲缘关系进程间共享内存区的方法:

(1)内存映射文件:由open函数打开,然后调用mmap函数把得到的描述符映射到当前进程地址空间中的一个文件。数据载体是物理文件。
(2)共享内存区对象:先由shm_open打开一个Posix IPC名字(也可以是文件系统中的一个路径名),然后调用mmap将返回的描述符映射到当前进程的地址空间。数据载体是物体内存。 这两种方法都需要调用mmap,区别在于mmap获取描述符的手段。
进程间通信机制详解(4)——共享内存_第3张图片
一般使用共享内存区对象。

int shm_open(const char *name, int oflag, mode_t mode);
创建一个新的共享内存区对象或打开一个已经存在的共享内存区对象。
int shm_unlink(const char *name);
删除一个共享内存区对象,跟其他文件的unlink以及其他POSIX IPC的删除操作一样,对象的析构会等到该对象的所有引用全部关闭才会发生。
映射函数:mmap函数
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 
映射删除函数munmap
int munmap(void *addr, size_t length);
从某个进程的地址空间删除一个映射关系。其中addr参数是由mmap返回的地址,len是映射区的大小。

注: 共享内存需要同步,一般与信号量一起使用

参考:
宋宝华:世上最好的共享内存(Linux共享内存最透彻的一篇)
进程间通信——共享内存(Shared Memory)

你可能感兴趣的:(Linux)