【问题标题】:Can a managed process get terminated while writing to shared memory?托管进程在写入共享内存时会终止吗?
【发布时间】:2018-07-28 06:59:03
【问题描述】:

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

【问题讨论】:

  • 不,它是一个 OS 对象,它知道 RAM 页面已被映射。如果操作系统也无法完成工作,您可能会丢失数据,例如断电。
  • @Hans,我添加了一个代码示例来演示我的问题/问题。对我来说,这与丢失数据无关,而是在写入数据的进程在写入时终止时部分写入的数据。
  • 如果你不能确定在程序崩溃/终止之前 Write() 是否成功完成,那么你当然什么都不知道。 Write() 不是原子的。我怀疑您会发现在 MMF 中指定一个指示“忙于写入”的字节很有用。在写入之前将其设置为 1,之后设置为 0,现在您有了一个事实。
  • 为什么其他进程在任何时候访问一个区域(大于64位)并假设一致性?听起来你有一个损坏的协议(或者一个不存在的协议需要存在)
  • MMF 不一定对进程互操作有​​用。事实上,这是它最不实用的用途之一。

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


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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-28
    • 2014-12-12
    • 2013-11-18
    • 1970-01-01
    • 2011-01-06
    • 2021-12-12
    • 1970-01-01
    相关资源
    最近更新 更多