写入共享内存时,托管进程是否可以终止?

时间:2018-02-17 14:42:58

标签: c# .net shared-memory memory-mapped-files cer

我有几个(托管/ .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标志)时是否保护进程免于异常终止的问题。

1 个答案:

答案 0 :(得分: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就会告诉您一个进程在锁定时已经死亡,您需要恢复上一个编写器所做的更改。