【发布时间】:2015-02-16 13:24:36
【问题描述】:
我想在 C 语言中为我在 BSD 操作系统上运行的进程实现一种有效的文件复制技术。到目前为止,该功能是使用读写技术实现的。我试图通过使用内存映射文件复制技术对其进行优化。
基本上,我将分叉一个进程,它同时映射 src 和 dst 文件,并对从 src 到 dst 的指定字节执行 memcpy()。 memcpy() 返回后进程退出。这里是否需要 msync(),因为当我实际调用带有 MS_SYNC 标志的 msync 时,该函数需要很长时间才能返回。 MS_ASYNC 标志也有相同的行为?
i) 所以总结一下避免 msync() 是否安全?
ii) 有没有其他更好的方式在 BSD 中复制文件。因为bsd好像是不支持sendfile()或者splice()?还有其他等价物吗?
iii) 有没有简单的方法来实现我们自己的零拷贝技术来满足这个要求?
我的代码
/* mmcopy.c
Copy the contents of one file to another file, using memory mappings.
Usage mmcopy source-file dest-file
*/
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
char *src, *dst;
int fdSrc, fdDst;
struct stat sb;
if (argc != 3)
usageErr("%s source-file dest-file\n", argv[0]);
fdSrc = open(argv[1], O_RDONLY);
if (fdSrc == -1)
errExit("open");
/* Use fstat() to obtain size of file: we use this to specify the
size of the two mappings */
if (fstat(fdSrc, &sb) == -1)
errExit("fstat");
/* Handle zero-length file specially, since specifying a size of
zero to mmap() will fail with the error EINVAL */
if (sb.st_size == 0)
exit(EXIT_SUCCESS);
src = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fdSrc, 0);
if (src == MAP_FAILED)
errExit("mmap");
fdDst = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fdDst == -1)
errExit("open");
if (ftruncate(fdDst, sb.st_size) == -1)
errExit("ftruncate");
dst = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdDst, 0);
if (dst == MAP_FAILED)
errExit("mmap");
memcpy(dst, src, sb.st_size); /* Copy bytes between mappings */
if (msync(dst, sb.st_size, MS_SYNC) == -1)
errExit("msync");
enter code here
exit(EXIT_SUCCESS);
}
【问题讨论】:
-
需要。如果您不执行
msync(2)。您无法保证在您munmap(2)文件时您的更改已刷新回 fs。 -
谢谢,但 msync() 似乎需要相当长的时间,有没有有效的方法来做到这一点?
-
我对 BSD 不太熟悉,无法提供权威的答案,抱歉。
-
msync只是等待数据提交到磁盘(如fsync)。不介意的可以跳过。 -
查看 /bin/cp (svnweb.freebsd.org/base/head/bin/cp) 的 freebsd 源代码表明,它们仅对源文件执行 mmap(2),并且仅当源大小为 8M 或更小时,然后只需使用 write(2) 来发出目标数据。你确定你能做得更好?你量过吗?有时,完善的系统实用程序的执行人员可以很好地融合可移植性和性能。