windows 文件系统不提供 c#strict/sequential/causal 等分布式一致性保证,仅承诺写入顺序可见性与缓存一致性;.net 文件操作依赖底层 windows api,需应用层通过排他打开、flush(true)、原子重命名等手段实现所需语义。

Windows 文件系统本身不提供 C#Strict / Sequential / Causal 一致性保证
这些术语(C#Strict、Sequential、Causal)是分布式系统或内存模型里的概念,不是 Windows 或 .NET 文件 I/O 的设计维度。.NET 的 FileStream、File.WriteAllText 等操作,底层依赖的是 Windows API(如 CreateFile、WriteFile),而 Windows 文件系统(NTFS、ReFS)只承诺「写入顺序可见性」和「缓存一致性」,不实现分布式一致性模型。
常见误解是:以为加了 FileOptions.WriteThrough 或 FileOptions.NoBuffering 就能获得类似 Sequential 的全局顺序语义——其实不能。它们只控制本地 I/O 路径是否绕过系统缓存,不影响多进程/多节点间的观察顺序。
-
FileOptions.WriteThrough:强制数据落盘(跳过系统页缓存),但不保证元数据(如文件长度、时间戳)同步刷新 -
FileOptions.NoBuffering:要求缓冲区对齐、大小对齐,绕过内核缓存,但仅限单次写入原子性,不构成跨调用的顺序约束 - 多个进程同时写同一文件时,Windows 不保证操作的全局执行顺序;谁先刷盘、谁先更新
FILE_END_OF_FILE_INFORMATION,取决于调度、缓存策略和磁盘队列
多线程写同一文件时,.NET 默认行为没有内存模型级顺序保障
即使在单进程内,多个线程调用 FileStream.Write 到同一个打开的 FileStream 实例,.NET 也不自动做内存屏障或顺序化——除非你显式同步。这是因为 FileStream 本身不是线程安全的写入目标(读可以并发,写不行)。
典型错误现象:FileStream.Position 混乱、写入覆盖、部分字节丢失,尤其在未禁用缓冲(bufferSize=1)或未调用 Flush() 时更明显。
- 必须用
lock或SemaphoreSlim控制写入临界区,不能依赖FileStream自身 -
Position是客户端维护的逻辑偏移,不是磁盘上的绝对位置;并发修改会导致它与实际文件指针脱节 - 如果需要严格追加,优先用
FileMode.Append+FileAccess.Write,它会在每次Write前调用SetFilePointer到 EOF,但仍有竞态窗口(两次调用之间可能被其他进程截断)
跨进程/跨机器一致性的实际落地靠应用层协议,不是靠 .NET IO 参数
当你看到“Causal consistency”需求,比如 A 进程写完日志后 B 进程必须看到新内容,Windows 文件系统不负责这个。它只保证:如果你用 FlushFileBuffers(对应 FileStream.Flush(true)),那么该句柄的写入已提交到磁盘控制器;但其他进程是否立刻 ReadFile 到最新数据,取决于它们是否重新 SetFilePointer、是否自己也用了缓存、甚至是否触发了 SMB 缓存一致性协议(在共享文件夹场景下)。
- SMB 协议有
oplock和lease机制,但 .NETFileStream不暴露控制权;默认是Level2 oplock,意味着其他客户端读缓存可能 stale - 想强同步?得用信号文件(如写完
log.txt再 touchlog.txt.done)、命名管道、或直接上MemoryMappedFile配合事件(EventWaitHandle) -
FileSystemWatcher不可靠:它基于 NTFS 日志,可能丢事件、延迟高、无法区分“写完成”和“写开始”
真正影响一致性的三个可控开关
别纠结一致性模型名词,盯住这三个点就够了:
-
FileOptions.WriteThrough:降低丢失风险,但性能差;适用于关键日志头写入,非全量数据 -
FileStream.Flush(true):等价于FlushFileBuffers,确保当前句柄所有缓存数据落盘;但不阻塞其他句柄的操作 - 关闭
FileShare.Write:强制排他打开(FileShare.None),避免其他进程并发写;这是最简单有效的“本地一致性锁”,代价是牺牲并发度
复杂点在于:这些开关都只管“单次写入是否落盘”,不管“多处写入的相对顺序”——后者必须由应用自己用原子重命名(File.Move 替换旧文件)、版本号或 WAL 日志来建模。文件系统只是块设备的封装,不是分布式协调器。










