创建一个新文件避免竞争条件
Creating a new file avoiding race conditions
我需要开发一个 C++ 例程来执行这个看似微不足道的任务:仅当文件不存在时才创建文件,否则会出现 nothing/raise 错误。
因为我需要避免竞争条件,所以我想使用 "ask forgiveness not permission" 原则(即尝试预期的操作并检查它是否成功,而不是提前检查先决条件),据我所知, 是用于此目的的唯一可靠且可移植的方法 [Wikipedia article][an example with getline].
仍然,我找不到在我的案例中实现它的方法。我能想到的最好办法是在 app
模式下打开 fstream
(或 fopen
ing with "a"
),用 tellp
检查输出位置(C++ ) 或 ftell
(C) 并在该位置不为零时中止。然而,这有两个缺点,即如果文件存在,它会被锁定(虽然时间很短)并且它的修改日期会被更改。
我检查了 ios_base::openmode
与 fstream
的其他可能组合,以及 fopen
的 mode
字符串,但没有找到适合我需要的选项。在 C 和 C++ 标准库以及 Boost 文件系统中的进一步搜索证明没有结果。
有人可以指出一种不依赖 OS 特定函数的稳健方式(没有附带影响,没有竞争条件)执行我的任务的方法吗?
我的具体问题在 Windows 中,但首选便携式解决方案。
编辑:BitWhistler 的回答完全解决了 C 程序的问题。尽管如此,令我惊讶的是似乎不存在 C++ 惯用的解决方案。正如 Andrew Henle 所提议的那样,任何一个都将 open
与 O_EXCL
属性一起使用,但是它是 OS 特定的(在 Windows 中,该属性似乎被称为 _O_EXCL
带有额外的下划线 [MSDN]) 或单独编译 C11 文件并将其与 C++ 代码链接。此外,获得的文件描述符无法转换为流,除非具有非标准扩展名(例如 GCC 的 __gnu_cxx::stdio_filebuf
)。我希望 C++ 的未来版本将实现 "x"
子属性,并可能实现文件流的相应 ios::
修饰符。
新的 C 标准(C2011,它不是 C++ 的一部分)添加了一个新的标准子说明符("x"),它可以附加到任何 "w" 说明符(形成 "wx"、"wbx"、"w+x" 或 "w+bx"/"wb+x")。如果文件存在,此子说明符将强制函数失败,而不是覆盖它。
我需要开发一个 C++ 例程来执行这个看似微不足道的任务:仅当文件不存在时才创建文件,否则会出现 nothing/raise 错误。
因为我需要避免竞争条件,所以我想使用 "ask forgiveness not permission" 原则(即尝试预期的操作并检查它是否成功,而不是提前检查先决条件),据我所知, 是用于此目的的唯一可靠且可移植的方法 [Wikipedia article][an example with getline].
仍然,我找不到在我的案例中实现它的方法。我能想到的最好办法是在 app
模式下打开 fstream
(或 fopen
ing with "a"
),用 tellp
检查输出位置(C++ ) 或 ftell
(C) 并在该位置不为零时中止。然而,这有两个缺点,即如果文件存在,它会被锁定(虽然时间很短)并且它的修改日期会被更改。
我检查了 ios_base::openmode
与 fstream
的其他可能组合,以及 fopen
的 mode
字符串,但没有找到适合我需要的选项。在 C 和 C++ 标准库以及 Boost 文件系统中的进一步搜索证明没有结果。
有人可以指出一种不依赖 OS 特定函数的稳健方式(没有附带影响,没有竞争条件)执行我的任务的方法吗? 我的具体问题在 Windows 中,但首选便携式解决方案。
编辑:BitWhistler 的回答完全解决了 C 程序的问题。尽管如此,令我惊讶的是似乎不存在 C++ 惯用的解决方案。正如 Andrew Henle 所提议的那样,任何一个都将 open
与 O_EXCL
属性一起使用,但是它是 OS 特定的(在 Windows 中,该属性似乎被称为 _O_EXCL
带有额外的下划线 [MSDN]) 或单独编译 C11 文件并将其与 C++ 代码链接。此外,获得的文件描述符无法转换为流,除非具有非标准扩展名(例如 GCC 的 __gnu_cxx::stdio_filebuf
)。我希望 C++ 的未来版本将实现 "x"
子属性,并可能实现文件流的相应 ios::
修饰符。
新的 C 标准(C2011,它不是 C++ 的一部分)添加了一个新的标准子说明符("x"),它可以附加到任何 "w" 说明符(形成 "wx"、"wbx"、"w+x" 或 "w+bx"/"wb+x")。如果文件存在,此子说明符将强制函数失败,而不是覆盖它。