一个线程写入一个文件(甚至删除它),另一个线程同时为该文件调用sendfile()以获得重叠位置。
这里的预期行为是什么?
另外,如果我的理解是正确的,sendfile调用只会向socket添加一条记录(文件描述,位置,长度)并返回给调用者。 (还没有复制到socket的缓冲区吗?),所以即使sendfile()在修改文件之前返回,OS依赖文件存在直到文件完全发送。
那么在发送文件之前修改的结果是什么?
答案 0 :(得分:3)
预期的行为是结果不可预测。 sendfile()
不是原子的,它实际上等同于编写自己的循环,从文件描述符调用read()
并在套接字描述符上调用write()
。如果某个其他进程在此过程中写入文件,您将获得旧内容和新内容的混合。可以把它想象成一个方便的功能,虽然它也应该显着提高效率,因为它不需要多个系统调用,并且可以直接在文件缓冲区和套接字缓冲区之间复制,而不是在应用程序之间来回复制缓冲区。因此,漏洞窗口应该小于read/write
循环,但它仍然存在。
要避免此问题,您应该在执行写入的进程和调用sendfile()
的进程之间使用文件锁定。所以序列应该是:
lock the file
call sendfile()
unlock the file
并且写作过程应该:
lock the file
write to the file
unlock the file
编辑:
实际上,它看起来并不简单,因为sendfile()
将套接字缓冲区链接到文件缓冲区缓存,而不是将其复制到内核中。由于sendfile()
没有等待发送数据,因此在文件返回后修改文件仍然会影响发送的内容。您需要检查应用层确认是否已收到所有数据。有关解释这些详细信息的文章摘录,请参阅Minimizing copies when writing large data to a socket。