托管进程在写入共享内存时是否会终止?

Can a managed process get terminated while writing to shared memory?

我有几个(托管/.NET)进程通过环形缓冲区进行通信,环形缓冲区通过 MemoryMappedFile class 保存在共享内存中(只有内存没有文件映射)。我从 SafeBuffer 参考资料中得知,向该内存写入结构由 CER(约束执行区域)保护,但是如果写入过程在这样做时被 OS 异常终止怎么办?这会导致结构只被部分写入吗?


    struct MyStruct
    {
      public int A;
      public int B;
      public float C;
    }

    static void Main(string[] args)
    {
      var mappedFile = MemoryMappedFile.CreateOrOpen("MyName", 10224);
      var accessor = mappedFile.CreateViewAccessor(0, 1024);
      MyStruct myStruct;
      myStruct.A = 10;
      myStruct.B = 20;
      myStruct.C = 42f;
      // Assuming the process gets terminated during the following write operation.
      // Is that even possible? If it is possible what are the guarantees   
      // in regards to data consistency? Transactional? Partially written?
      accessor.Write(0, ref myStruct); 
      DoOtherStuff(); ...
    }

很难模拟/测试这个问题是否真的存在,因为写入内存的速度非常快。但是,这肯定会导致我的共享内存布局出现严重的不一致,并且有必要通过校验和或某种页面翻转来解决这个问题。

更新:

查看第 1053 行

https://referencesource.microsoft.com/#mscorlib/system/io/unmanagedmemoryaccessor.cs,7632fe79d4a8ae4c

它基本上归结为一个问题,即在 CER 块(设置了 Consistency.WillNotCorruptState 标志)中执行代码时,进程是否受到保护免于异常终止。

是的,进程可以随时停止。

SafeBuffer<T>.Write方法最终调用到

[MethodImpl(MethodImplOptions.InternalCall)]
[ResourceExposure(ResourceScope.None)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static extern void StructureToPtrNative(/*ref T*/ TypedReference structure, byte* ptr, uint sizeofT);

这基本上是 memcpy(ptr, structure, sizeofT)。由于未对齐的写入永远不会是原子的,除了字节之外,如果您的进程在写入值时在中间终止,您将 运行 陷入问题。

当进程通过 TerminateProcess 或未处理的异常以硬方式终止时,不会执行任何 CER 或相关内容。在这种情况下不会发生优雅的托管关闭,您的应用程序可以在重要事务的中间停止。您的共享内存数据结构将处于孤立状态,您可能使用的任何锁将 return WaitForSingleObject WAIT_ABANDONED 中的下一个服务员。这样 Windows 告诉你一个进程在获取锁时已经死亡,你需要恢复最后一个写入者所做的更改。