rename() 是原子的吗?
- 2024-11-01 08:41:00
- admin 原创
- 72
问题描述:
我无法通过实验来检查这一点,也无法从手册页中收集它。
假设我有两个进程,一个将文件 1 从目录 1 移动(重命名)到目录 2。假设另一个同时运行的进程将目录 1 和目录 2 的内容复制到另一个位置。复制是否可能以目录 1 和目录 2 都显示文件 1 的方式进行 - 即目录 1 在移动之前被第一个进程复制,而目录 2 在移动之后被第一个进程复制。
基本上 rename() 是一个原子系统调用?
谢谢
解决方案 1:
是也不是。
假设操作系统没有崩溃,rename() 是原子的。它不能被任何其他文件系统操作拆分。
如果系统崩溃,您可能会看到 ln() 操作。
另请注意,在网络文件系统上操作时,操作成功后可能会收到 ENOENT。本地文件系统不会出现这种情况。
解决方案 2:
这是一个非常晚的答案,但是……rename()
是原子的,但不是你的问题的意思。在 Linux 下, rename(2)
说:
然而,覆盖时可能会出现一个窗口,其中 oldpath 和 newpath 都引用被重命名的文件。
但rename()
在一个非常重要的意义上它仍然是原子的:如果你用它来覆盖一个文件,那么你最终会得到旧版本或新版本,而不会得到其他任何东西。
[更新:但正如 @jonas-wielicki 在评论中指出的那样,您需要确保您重命名的文件实际上具有最新的内容、使用fsync()
和朋友。]
如果 newpath 已经存在,它将被原子替换(取决于一些条件;请参阅下面的错误),以便其他尝试访问 newpath 的进程不会发现它丢失。
如果您看到错误,您会发现重命名可能会失败,但它永远不会破坏原子性。
这些都是来自 Linux 手册页。我不知道的是,如果你rename()
在服务器运行不同操作系统的网络文件系统上执行操作。那么客户端是否有希望保证原子性?我对此表示怀疑。
解决方案 3:
我不确定你问题的“基本上”部分是否有效。除非你在两者之间有某种同步,否则重命名的原子性并不重要。如果目录副本在重命名之前到达那里,那么你将在两个地方都有 file1。
我不确定您指的是线程还是进程,但如果两者都有锁定机制,那么线程锁是迄今为止最简单的,因为它们不必跨越进程边界。
解决方案 4:
gnu libc手册说
rename 的一个有用功能是 newname 的含义会“自动”从任何以前存在的同名文件更改为其新含义(即,名为 oldname 的文件)。在旧含义和新含义之间,没有 newname 不存在的瞬间。如果在操作过程中发生系统崩溃,则两个名称可能仍然存在;但如果 newname 存在,它将始终完好无损。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件