C语言 如果进程终止但系统继续运行,WriteFile()将是原子的吗?



如果我的进程在一个随机的时刻被终止,但操作系统继续正常运行,Windows将保证对WriteFile的单个调用是原子的(又名全或无)吗?
或者我可以得到部分/撕裂的写?


注意:我特别不是在询问如何练习防御性编码的建议。

这是严格意义上的一个关于Microsoft Windows 操作系统本身行为的问题。

要100%完美地清晰我们可以显式地相信用户代码会正常运行没有未定义行为或任何类似的行为。假定所有进程终止都是通过定义良好的行为发生的,例如未处理的异常或对TerminateProcess的调用,内存损坏等。

还要特别注意,这里没有c++析构函数需要担心;这是c。

我希望所有关于用户代码的次要问题都能得到解决。

WriteFile当然是不是原子的情况下,你的进程被终止,而它正在执行,它甚至不是原子的,如果你的进程没有被杀死。

同样,"全部或不写"甚至不是原子写的正确定义。所有的都可以写入,但是混合着来自另一个进程的独立写入。如果要保证写操作是原子性的,那么必须保证(读作:lock)不会发生这种情况。

除了实现适当的原子性会带来相当多的额外麻烦,对普通日常用户来说几乎没有什么好处之外,您还可以从

中猜测WriteFile不是原子的:
  1. API文档中没有提及。你可以打赌,这将是突出提到,因为它是一个非常大的,显著的功能。
  2. 是否存在lpNumberOfBytesWritten参数。写操作仍然可能失败(例如磁盘已满),但如果保证函数是原子的,您将知道它成功或失败,并且您已经知道要写多少字节,因此返回该数字是不必要的。
  3. TxF的存在。虽然TxF所做的不仅仅是使单次写入原子化,但有理由认为,当"正常"的文件系统操作或多或少都是这样工作的时候,微软不会浪费大量的时间和金钱来实现这样一个野兽。
  4. 据我所知,没有其他主流操作系统能提供这样的保证。Linux确实在writev上提供了一种类型的原子性保证(但在write上没有),只要您的写操作不会与其他进程的写操作混杂在一起。但这与保证进程终止时的原子性完全不同。

然而,在FILE_FLAG_NO_BUFFERING打开的句柄上的重叠写在技术上是原子的,就进程终止而言(但就失败而言,例如磁盘已满或任何其他方面!)。诚然,这样说在实现细节上有点诡辩,并不是操作系统给出的实际保证,但从某种角度来看,这样说肯定是正确的。
不能终止正在执行未缓冲的重叠I/O操作的进程。这是因为操作系统正在将DMA传输到该进程的地址空间。这当然意味着不能终止进程,因为操作系统会回收物理页面。因此,当这样的I/O操作正在运行时,操作系统将拒绝终止进程。
您可以通过触发几个大的未缓冲的重叠请求(几GB)并尝试在任务管理器中杀死您的进程来验证这一点。只有当I/O完成时(也就是几秒钟后),它才会被杀死。当你第一次看到它发生时,你会感到非常惊讶,而且你也没有预料到!

最新更新