我想在C语言中实现一个有效的文件复制技术,在BSD OS上运行。 截至目前,function是使用读写技术来实现的。 我正试图使用内存映射文件复制技术进行优化。
基本上我将fork一个mmaps src和dst文件的进程,并将指定字节从src到mem的memcpy()。 进程在memcpy()返回后退出。 msync()在这里是必需的,因为当我实际上用MS_SYNC标志调用msync时,函数花费很多时间返回。 MS_ASYNC标志也是一样的行为?
我)总结一下,避免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()
不是必需的。
如果不指定msync()
,则操作系统在进程终止后在后台刷新内存映射的页面。 这在任何符合POSIX的操作系统上都是可靠的。
回答第二个问题:
通常情况下,在任何POSIX兼容操作系统(如BSD)上复制文件的方法是使用open()
/ read()
/ write()
和一些大小的缓冲区(例如16kb,32kb或64kb) 。 将数据从src读入缓冲区,将数据从缓冲区写入dest。 重复直到read(src_fd)
返回0字节(EOF)。
但是,根据您的目标,使用mmap()以这种方式复制文件可能是一个完全可行的解决方案,只要所处理的文件相对较小(相对于目标硬件和应用程序的预期内存限制) 。 mmap复制操作将需要文件的总物理内存大约2倍。 所以如果你想复制一个8MB的文件,你的应用程序将使用16MB来执行复制。 如果您希望使用更大的文件,那么这种重复可能会变得非常昂贵。
那么使用mmap()
还有其他优点吗? 其实没有
使用write()
将数据直接write()
文件时,操作系统通常会比使用mmap页面更慢。 这是因为操作系统会在页面刷新之前有意识地优先处理其他事情,以保持系统对前台任务/应用程序的响应。
在将mmap页面刷新到磁盘(在后台)期间,系统突然断电的可能性将导致数据丢失。 当然,这也可能发生在使用write()
,但如果write()
完成得更快,那么出现意外中断的可能性就会降低。
调用msync()
时所观察到的长时间延迟大致是操作系统将复制的文件刷新到磁盘所需的时间。 当你不调用msync()它会发生在后台(而且也需要更长的时间,因为这个原因)。