os.open()在哪些系统/文件系统中是原子的?

9 投票
1 回答
3121 浏览
提问于 2025-04-17 17:03

这篇文章提到,

fd = os.open('foo.lock', os.O_CREAT|os.O_EXCL|os.O_RDWR)

“在大多数文件系统上是原子的”。这是真的吗(在Unix和Windows上)?在哪些文件系统上是这样?

文档指出,提到的标志在Unix和Windows上都可以使用,所以这看起来是一个很吸引人的跨平台文件锁定方法(这些标志O_CREATO_EXCL确保调用的进程会创建文件)。

1 个回答

6

对于符合UN*X标准的系统(也就是经过POSIX / IEEE 1003.1认证的系统),它们的行为是有保障的,因为OpenGroup的规范对open(2)有明确的要求。引用如下:

O_EXCL
如果同时设置了O_CREAT和O_EXCL,那么如果文件已经存在,open()就会失败。检查文件是否存在以及在文件不存在时创建文件的过程是原子性的,也就是说在同一目录下,其他线程如果也在用O_EXCL和O_CREAT打开同一个文件名时,这个过程不会被打断。如果设置了O_EXCL和O_CREAT,并且路径名是一个符号链接,open()会失败,并将errno设置为[EEXIST],无论符号链接的内容是什么。如果只设置了O_EXCL而没有设置O_CREAT,结果是未定义的。

常见的UN*X和类UN*X系统(比如Linux、MacOSX、*BSD、Solaris、AIX、HP/UX)肯定是这样工作的。

由于Windows的API没有直接的open()函数,因此在那里的库函数是基于本地API重新实现的,但可以保持相同的语义。

我不知道有哪些广泛使用的系统符合这个标准;虽然QNX没有获得POSIX认证,但它的文档中对open()的说明是一样的。*BSD的手册没有明确提到“原子性”,但Free/Net/OpenBSD都实现了这一点。甚至像SymbianOS这样的特殊系统(它和Windows一样没有UN*X风格的open系统调用)也能做到原子打开/创建。

如果想要更有趣的结果,可以试着找一个有open()实现上述语义的操作系统或C运行时库……并且Python可以在上面运行并使用线程(这就把MSDOS给抓住了……)。

编辑:我的帖子特别关注“哪些操作系统具有open的这个特性?”——答案是“几乎所有的系统都有”。不过关于文件系统,情况就不同了,因为网络文件系统——无论是NFS、SMB/CIFS还是其他,通常不总是维护O_EXCL,因为这可能导致拒绝服务(如果一个客户端执行open(..., O_EXCL, ...)然后停止与文件服务器通信或被关闭,其他人就会被锁定)。

撰写回答