使用sendfile()/ fcopyfile()从共享内存映射对象复制数据

时间:2017-05-13 22:56:01

标签: c++ posix shared-memory mmap file-descriptor

是否有可能 - 如果这么谨慎 - 使用sendfile()(或其Darwin / BSD堂兄fcopyfile())直接在共享内存对象和文件之间传送数据?

sendfile()fcopyfile()这样的函数可以执行完全支持这种数据传输的所有机制必需品,而不会留下内核空间 - 在调用时会传递两个开放描述符,一个源和一个目标。这些功能,他们从那里接受它。

其他复制数据的方法总是要求人们在核心空间和用户空间之间的边界上进行手动操作;这种上下文切换本质上是非常昂贵的,在性能方面。

我无法找到关于使用共享内存描述符作为参数的主题的确定性:没有赞成或反对这种做法的文章;各man页中没有任何内容;没有推文公开考虑sendfile()共享内存描述符有害; & c ......但是,我认为我应该可以这样做:

char const* name = "/yo-dogg-i-heard-you-like-shm"; /// only one slash, at zero-index
int len = A_REASONABLE_POWER_OF_TWO;                /// valid per shm_open()
int descriptor = shm_open(name, O_RDWR | O_CREAT, 0600);
int destination = open("/tmp/yodogg.block", O_RDWR | O_CREAT, 0644);
void* memory = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, descriptor, 0);
off_t bytescopied = 0;
sendfile(destination, descriptor, &bytescopied, len);
/// --> insert other stuff with memset(…), memcopy(…) &c. here, possibly
munmap(memory, len);
close(descriptor); close(destination);
shm_unlink(name);

......这是误入歧途还是有效的技术?

如果是后者,可以在复制数据之前调整内存中共享映射的大小吗?

编辑:我正在开发此调查涉及macOS 10.12.4的项目;我的目标是在Linux上工作,最终具有FreeBSD互操作性。

1 个答案:

答案 0 :(得分:3)

在两个"事物之间复制数据"映射到内存中 - 就像上面的例子一样 - 确实需要将内容从内核复制到用户空间然后再复制。不,你不能真正使用sendfile(2)系统调用发送到文件描述符,我很害怕。

但你应该能够这样做:

  1. 创建共享内存对象(或文件,真的;由于第二步,它将在内存中共享
  2. 使用MAP_SHARED将其映射到内存中;你会得到一个指针
  3. 打开目标文件
  4. write(destination_fd,source_pointer,source_length)
  5. 在这种情况下,写入系统调用不需要将数据复制到您的进程中。但不确定实际的性能特征是什么。聪明地使用madvise(2)可能有所帮助。