我无法通过实验来检查这个问题,也无法从手册中收集到相关信息。
假设我有两个进程,一个将文件1从目录1移动(rename)到目录2。同时另一个进程正在复制目录1和目录2的内容到另一个位置。是否可能出现这样的情况,即在第一个进程移动之前复制了目录1,并且在移动后复制了目录2,导致目录1和目录2都显示文件1。
基本上,rename()是原子系统调用吗?
谢谢。
我无法通过实验来检查这个问题,也无法从手册中收集到相关信息。
假设我有两个进程,一个将文件1从目录1移动(rename)到目录2。同时另一个进程正在复制目录1和目录2的内容到另一个位置。是否可能出现这样的情况,即在第一个进程移动之前复制了目录1,并且在移动后复制了目录2,导致目录1和目录2都显示文件1。
基本上,rename()是原子系统调用吗?
谢谢。
是和否。
假设操作系统没有崩溃,rename()是原子性的。它不能被任何其他文件系统操作拆分。
如果系统崩溃,您可能会看到ln()操作。
还要注意,在网络文件系统上操作时,当操作成功时,您可能会收到ENOENT错误。本地文件系统不会这样做。
rename()
是原子的,但不是你问题中的那种。 在Linux下,rename(2)
说:
但是然而,在覆盖时,oldpath和newpath都指向正在重命名的文件的时间窗口可能会出现。
rename()
在非常重要的意义上仍然是原子的:如果您使用它来覆盖文件,则最终将得到旧版本或新版本之一,没有其他东西。
[更新:但正如@jonas-wielicki在评论中指出的那样,您需要确保正在重新命名的文件实际上具有最新的内容,使用fsync()
等工具进行同步]
如果看到 ERRORS,您会发现重命名可能会失败,但永远不会破坏原子性。如果newpath已经存在,它将被原子替换(受几个条件的限制;请参见下面的错误),因此没有另一个进程尝试访问newpath会发现它丢失的时刻。
rename()
,同时还有另一个进程在将"directory1和directory2的内容复制到另一个位置"。第二个进程至少需要进行不同的“读取directory1的内容”和“读取directory2的内容”的步骤,甚至在开始任何复制/重命名操作之前,正是这些步骤会与第一个进程中的rename()
竞争。 - cafGNU libc 手册中提到:
rename的一个有用特性是,newname的含义会“原子地”从之前任何已存在的同名文件更改为其新含义(即被称为oldname的文件)。在旧含义和新含义之间不存在newname不存在的瞬间。如果操作期间系统崩溃,则可能同时存在两个名称;但只要newname存在,它就始终完好无损。