在Linux下共享内存映射

4

动机

我想编写一对程序,其中一个程序读取数据并将其转换为内部格式,另一个程序将内部格式转换为其他格式。作为练习,我想在不使用管道的情况下编写这些程序之间的交互。我更喜欢使用信号和共享内存。

我的要求

我有程序A和程序B,其中A调用B。我如何

  1. 在程序A中创建一个内存块
  2. 从程序A调用程序B,向其提供有关在哪里找到内存块的信息
  3. 从两个程序中使用内存块。

具体地说,A解码自定义视频格式,并将单个未压缩帧放入共享缓冲区。B从缓冲区读取并将其编码成输出流。解码器每秒解码高达100帧,这大约是500 MiB/s的内存流量。由于数据必须被复制得太频繁,而且缓冲区大小并不精确,因此管道速度很慢。

我想会起作用的方法

我的想法是使用mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0)来创建一个共享内存段。问题是,execve(2)的manpage声明:

内存映射不会被保存(mmap(2))。

那么,我该如何与其他程序共享该内存?把两个功能放入一个程序中并使用fork是否更好?


3
你应该将此视为一次学习练习,但请注意,使用共享状态(特别是共享内存)使事情正常运行过于困难,即使代价很大也应该避免。很可能内存共享本身就更加昂贵。作为友好的提醒 :) - Magnus Hoff
@Magnus 你认为应该如何处理呢?共享状态是两个未压缩像素数据缓冲区。一个进程解码图像,另一个进程编码。使用管道完全破坏了并行性,因为512字节的缓冲区太小了。 - fuz
这对于练习来说还不错,但共享内存通常是一个非常糟糕的想法。你可以考虑更高级的IPC,比如套接字、命名管道或Zero-MQ。 - singpolyma
处理大量数据并不是一件疯狂的事情。例如,SkypeKit使用共享内存进行视频传输,因为它可以提供高吞吐量而无需其他IPC机制的开销。 - nneonneo
@nneonneo,我添加了一段关于数据大小的内容。 - fuz
显示剩余3条评论
1个回答

5
*nix系统有多个用于共享内存的API:
  • BSD:使用mmap()。要在不相关的进程之间共享内存,您需要将其与文件关联起来。您还可以使用MAP_ANONYMOUSfork()在相关进程之间共享内存(但确保对于可移植性使用-1作为fd)。
  • System V:(一些人真的不喜欢这个)使用shmget()创建/获取对共享内存区域的引用,通过shmat()连接到它,通过shmdt()分离,使用shmctl()标记删除。您通过一个键标识共享内存区域,该键应该是唯一的。
  • POSIX:使用shm_open(),然后从返回的文件描述符中使用mmap()

1
支持文件的mmap()用于共享内存不仅适用于BSD,也适用于POSIX。使用MAP_SHARED映射,共享对象在RAM中,只有在调用msync()或者存在大量内存压力且映射具有最近未访问的页面时,才会将页面刷新到磁盘上。个人认为,在处理大量数据时,使用文件的mmap(..,MAP_SHARED,..)是最佳选择。 - Nominal Animal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接