【问题标题】:What is the expected behaviour if file is written/altered while sendfile() is in progress如果在 sendfile() 正在进行时写入/更改文件,预期的行为是什么
【发布时间】:2017-12-29 14:11:23
【问题描述】:

一个线程写入文件(甚至删除它),另一个线程同时为该文件调用 sendfile() 以获取重叠位置。

这里的预期行为是什么?

另外,如果我的理解是正确的,sendfile 调用只会向套接字添加一条记录(文件描述、位置、长度)并返回给调用者。 (还没有复制到套接字的缓冲区?),所以即使 sendfile() 在修改文件之前返回,操作系统也依赖于文件的存在,直到文件被完全发送。

那么在文件发送之前任何修改的结果是什么?

【问题讨论】:

  • 即使你删除了一个打开的文件,内核对该文件的句柄(以及你的进程的fd)将保持文件“活动”直到它被关闭。这也是您可以“移动”打开文件而不影响其fd 句柄的原因。至于由编辑引起的比赛条件……嗯,这是一场比赛。如果 sendfile 在编辑后运行,它将在编辑后的版本上运行。
  • 写入可能会被正在运行的程序、操作系统甚至 HD 控制器缓冲。甚至可能是所有三个,连续。最佳做法是在多线程程序中读取和写入同一个文件时添加原子保护。
  • @usr2564301 HD 控制器与应用程序无关。 Linux 有统一的缓冲区缓存,所有进程使用相同的内核文件缓冲区。

标签: c linux sockets


【解决方案1】:

预期的行为是结果是不可预测的。 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 获取解释这些细节的文章的摘录。

【讨论】:

  • 你知道 mmap 的行为是否相同吗?无效 * p = mmap(fd0);发送(fd1,p,0,len)。那么,有没有办法确保数据已发送?我的意思是再次安全地开始编辑文件。不过,一种方法可能是依靠客户的确认。对此有何想法?
  • send()sendfile()返回时,我认为所有的数据都已经复制到了socket缓冲区中,所以修改文件是安全的。我认为您遇到的问题是另一个进程在您调用 sendfile() 的同时修改了文件。
  • send() 就是这样工作的,但我找到了这个链接,接受的答案说 sendfile 和 mmap 工作方式不同,但答案中的原始论文链接不起作用,所以我不确定这种行为。 stackoverflow.com/questions/20008707/…
  • 嗯,看来这是个问题。所以你可能是对的,你需要等待接收者在允许写入之前确认接收到文件。
  • 会很好,但听起来不像。
猜你喜欢
  • 2017-09-01
  • 2020-01-10
  • 1970-01-01
  • 1970-01-01
  • 2012-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
相关资源
最近更新 更多