Linux上的原子文件创建?

5

如果文件不存在,我需要创建一个文件,这样尝试创建此文件的另一个进程将失败。在实际数据写入文件之前,我希望该文件被视为“已创建”。

我了解到使用open()O_EXCL标志似乎可以解决这个问题,但是我有几个问题:

  1. 您是否具有使用此技术的经验?它有多好?(我想我无法获得数据库级别的原子性,但是足够好就可以)
  2. 我应该在open()后立即关闭文件,以便被认为已创建,然后重新打开进行写入吗?
  3. 有哪些细节需要注意?
2个回答

9
open() man page中提到,您的方法可能在NFS上失败。
从O_EXCL部分可以看出:
当与O_CREAT一起使用时,如果文件已经存在,则会出现错误并且open()将失败。在此情况下,符号链接存在,而不管它指向何处。O_EXCL在NFS文件系统上是有问题的;依赖它执行锁定任务的程序将包含竞争条件。
该页面建议采用更通用的解决方案:
使用锁文件来执行原子文件锁定的解决方案是在同一文件系统上创建一个唯一的文件(例如,包括主机名和pid),使用link(2)创建到锁文件的链接。如果link()返回0,则锁定成功。否则,在唯一文件上使用stat(2)检查其链接计数是否增加到2,如果是,则锁定也成功。
有关各种问题和方法的更多详细信息,请参见本网页中的“使用文件作为锁定”部分。

是的,我看到了这个,所以我的问题是针对我不使用NFS的情况。此外,替代方案对我来说很模糊 - 如何通过为每个进程创建一个唯一的文件来帮助2个进程看到它们正在尝试使用相同的文件?如果您理解这一点,能否解释一下? - davka
NFS上的链接和取消链接调用不是幂等或同步的。请改用mkdir。 - tchrist
1
@davka:这个方法使用链接作为锁。无论链接当前指向哪个文件,该文件都“拥有”锁定权。(每个文件对于一个进程是唯一的,因此您可以进行进程锁定)。 - payne
@davka - fcntl 应该可以在 NFS 上工作,因此您可以使用它来在写入时同步您的进程,而不是在打开时。 - aaz

1

POSIX说:

如果设置了O_CREAT和O_EXCL,则open()将失败,如果文件已存在。 对于文件的存在检查以及如果不存在则创建文件应与其他线程原子化执行 在相同目录中使用O_EXCL和O_CREAT设置命名相同的文件的open()。

因此,使用O_EXCL的其他进程将在创建后立即考虑它已打开。


谢谢,这更加明确了。我想知道在 open() 之后文件是否被认为是“已创建”。这似乎表明是的。 - davka
@davka - 我猜它的意思是“是的,应该是这样”,但如果没有这个保证,我认为根本没有必要设置标志。BSD manpages说:“这可以用来实现一个简单的独占式访问锁定机制。”如果没有这个保证,那就行不通了。 - aaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接