是否有可能——如果谨慎的话——使用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 互操作。
最佳答案
在映射到内存中的两个“事物”之间复制数据——如上例所示——确实需要将事物从内核复制到用户空间,然后再复制回来。不,恐怕您不能真正使用 sendfile(2) 系统调用来发送到文件描述符。
但是你应该可以这样做:
- 创建共享内存对象(或者一个文件,真的;由于第二步,它无论如何都会在内存中共享
- 使用 MAP_SHARED 将其映射到内存中;你会得到一个指针
- 打开目标文件
- 写(目的地_fd,源指针,源长度)
在这种情况下,写入系统调用不需要将数据复制到您的进程中。不过,不确定实际的性能特征是什么。明智地使用 madvise(2) 可能会有所帮助。
关于c++ - 使用 sendfile()/fcopyfile() 从共享内存映射对象复制数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43958735/