1

我有几个(托管/.NET)进程通过一个环形缓冲区进行通信,该缓冲区通过 MemoryMappedFile 类保存在共享内存中(只是内存没有文件映射)。我从 SafeBuffer 参考源中知道,将结构写入该内存受到 CER(约束执行区域)的保护,但是如果写入过程在这样做时被操作系统异常终止怎么办?这会导致结构仅被部分写入吗?


    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 标志)时是否保护进程免受异常终止的问题。

4

1 回答 1

1

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

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 或相关内容。在这种情况下不会发生正常的托管关闭,您的应用程序可以在重要事务的中间停止。您的共享内存数据结构将处于孤立状态,您可能使用的任何锁都将返回下一个等待者WaitForSingleObject WAIT_ABANDONED。这样,Windows 会告诉您一个进程在获得锁定时已经死亡,您需要恢复最后一个写入者所做的更改。

于 2018-02-19T12:13:23.557 回答