【问题标题】:Is rename required by standard to be atomic?标准要求重命名是原子的吗?
【发布时间】:2016-11-10 22:37:33
【问题描述】:

当我试图回答这个问题时,出现了一个有趣的问题:

Is mv atomic on my fs?

rename() 函数要求按照标准是原子的吗?

POSIX standard for rename 的“基本原理”部分指出:

这个rename() 函数相当于普通文件 由 ISO C 标准定义。它的包含在这里扩展了 定义包括对目录的操作并指定行为 当新参数命名一个已经存在的文件时。 那个 规范要求函数的动作是原子的。

但是,rename 上的 latest publicly-available ISO C Standard 部分完整地指出:

7.21.4.2 rename 函数

概要

#include <stdio.h>
int rename(const char *old, const char *new);

说明

rename 函数使名称为 old 指向的字符串的文件从此名称中被称为 由new 指向的字符串给出。名为old 的文件没有 不再可以通过该名称访问。如果由字符串命名的文件指向 to by new 在调用 rename 函数之前存在, 行为是实现定义的。

退货

如果操作成功,rename 函数返回零,如果失败则返回非零,在这种情况下,如果文件存在 以前它仍然以其原始名称而闻名。

在 ISO C 标准的rename() 部分中,对于任何类型的原子性没有任何类型的明确要求。

在编写了许多依赖于 rename() 明显特定于实现的原子性的程序后,我认为原子性是一项要求,并对 C 标准中缺乏原子性感到惊讶。

但是 POSIX 标准说 ISO C 标准要求 rename() 是原子的。

解释?

【问题讨论】:

  • 您可能希望包含脚注 269。标题为 “Returns” 的段落可以解释为暗示原子性,并且注释 269 进一步支持了这一概念。
  • rename 是否在不同文件系统之间复制文件?如果不是,我希望它在可用的情况下使用硬链接,从而使操作在应用程序级别确实是原子的。如果它是 FS 或媒体级别的原子是另一个问题。
  • 这不是 POSIX 标准所说的。 “该规范”是指“扩展该定义以包括对目录的操作并指定新参数命名已存在的文件时的行为”,即 POSIX 标准的补充。特别是,“如果存在由 new 参数命名的链接,[...] 名为 new 的链接在整个重命名操作期间对其他线程保持可见,并引用到操作开始前 newold 引用的文件。"
  • @T.C. POSIX 标准声明“这个rename() 函数对于常规文件等同于ISO C 标准定义的函数。...该规范要求函数的操作是原子的。”这是非常明确的. POSIX 标准规定 ISO C 标准要求 rename() 是原子的。但据我所知,ISO C 标准中没有任何内容需要原子性。然而,POSIX 标准规定 ISO C 标准需要这种原子性。因此问题。
  • 我也可以使用省略号:“它包含在此处...指定新参数命名已存在的文件时的行为。该规范要求函数的动作是原子的。”

标签: c language-lawyer


【解决方案1】:

您在 POSIX 标准中对rename() 的引用来自(非规范)“基本原理”部分。主要条目——实际的规范材料——开始:

对于 rename():[CX] 此参考页面上描述的功能符合 ISO C 标准。此处描述的要求与 ISO C 标准之间的任何冲突都是无意的。本卷 POSIX.1-2008 遵循 ISO C 标准。

rename() 函数将更改文件的名称。 old 参数指向要重命名的文件的路径名。 new 参数指向文件的新路径名。 [CX] 如果new 参数不能解析为目录类型文件的现有目录条目,并且new 参数包含至少一个非&lt;slash&gt; 字符并且处理完所有符号链接后,以一个或多个尾随 &lt;slash&gt; 字符结尾,rename() 将失败。

条目的所有其余部分都在[CX](C 扩展)标签内,并讨论了其他特殊行为。

你引用的理由是:

rename() 函数对于常规文件等效于由 ISO C 标准定义的函数。它在这里的包含扩展了该定义以包括对目录的操作,并指定新参数命名已存在的文件时的行为。该规范要求函数的操作是原子的。

最后一句中提到的“那个规范”是扩展定义,包括对目录的操作规范和“当新参数命名一个已经存在的文件时”,而不是 C 标准中的规范,正如您所观察到的,它没有说明原子性(非常合理;有些系统可以支持 C 和 rename(),但无法支持 POSIX 更严格的原子性要求)。

我发现这正是T.C 在他们的comment 中提出的论点——我同意 T.C.

【讨论】:

  • 谢谢。所以答案是“不,rename() 不需要是原子的。”这是有道理的——但我问这个问题是因为我一直假设 rename 必须是原子的,当我找不到它时感到很惊讶。而且总是很难证明是否定的。
  • @AndrewHenle:正确,标准 C 不需要 rename() 是原子的。 POSIX 具有更严格(更详细和完整)的规则,因为它处理更多的文件类型。标准 C 甚至不知道目录、符号链接或 FIFO 是什么,更不用说它们如何与 rename() 交互了。
  • @AndrewHenle 不太正确 - 标准 C 不要求 rename 是原子的,但 POSIX 需要。关键语句是“如果新参数命名的链接存在,则应将其删除并将旧的重命名为新的。在这种情况下,名为新的链接应在整个重命名操作期间对其他线程保持可见,并引用所引用的文件在操作开始之前由新的或旧的。”
  • 这使得它在重命名为现有文件名时具有原子性。但是重命名为一个不存在的文件名呢? POSIX 中似乎没有任何东西需要它是原子的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-02
  • 2013-11-03
  • 1970-01-01
  • 1970-01-01
  • 2012-11-03
  • 2010-10-05
  • 2021-12-23
相关资源
最近更新 更多