重命名()原子?

问题描述 投票:38回答:4

我无法通过实验检查这一点,也无法从手册页中收集它。

假设我有两个进程,一个从directory1移动(重命名)file1到directory2。假设另一个并发运行的进程将directory1和directory2的内容复制到另一个位置。是否可能以这样的方式发生复制:directory1和directory2都将显示file1 - 即在移动之前复制directory1,在第一个进程移动之后复制directory2。

基本上是rename()是一个原子系统调用?

谢谢

linux file-rename atomicity vfs
4个回答
24
投票

是的,不是。

rename()是原子的,假设操作系统没有崩溃。它不能被任何其他文件系统op拆分。

如果系统崩溃,您可能会看到ln()操作。

另请注意,在网络文件系统上运行时,如果操作成功,您可能会获得ENOENT。本地文件系统无法做到这一点。


24
投票

这是一个非常晚的答案,但是......是的rename()是原子的,但不是你的问题。在Linux下,rename(2)说:

但是,当覆盖时,可能会有一个窗口,其中oldpath和newpath都引用要重命名的文件。

但是rename()在一个非常重要的意义上仍然是原子的:如果你用它来覆盖一个文件,那么你最终将使用旧版本或新版本而不是其他内容。

[更新:但正如@ jonas-wielicki在评论中指出的那样,你需要确保你重命名的文件实际上有最新的内容,使用fsync()和朋友。]

如果newpath已经存在,它将被原子替换(受一些条件限制;请参阅下面的错误),这样就没有任何一点可以尝试访问newpath的另一个进程会发现它丢失。

如果您看到ERRORS,您会发现重命名可能会失败,但它永远不会破坏原子性。

这完全来自Linux手册页。我不知道的是,如果您在网络文件系统上执行rename(),其中服务器运行不同的操作系统。客户是否希望保证原子性呢?我对此表示怀疑。


6
投票

我不确定你问题的“基本”部分是否有效。除非你们之间有某种同步,否则原子重命名的方式并不重要。如果目录副本在重命名之前到达那里,那么你将在两个地方都有file1。

我不确定你是否意味着线程或进程,但如果两者都有锁定机制,则线程锁是最简单的,因为它们不必跨越进程边界。


0
投票

gnu libc manual

重命名的一个有用特性是newname的含义从该名称的任何先前存在的文件“原子地”改变为其新含义(即,称为oldname的文件)。没有一个新名称不存在于旧意义和新意义之间。如果在操作期间发生系统崩溃,则两个名称都可能仍然存在;但如果newname存在,则newname将始终保持不变。

© www.soinside.com 2019 - 2024. All rights reserved.