C# 在写入共享内存时,托管进程能否终止?
我有几个(managed/.NET)进程通过一个环形缓冲区进行通信,该缓冲区通过MemoryMappedFile类保存在共享内存中(只是内存未映射文件)。我从SafeBuffer引用源知道,将结构写入该内存是由CER(受限执行区域)保护的,但如果写入过程在这样做时被操作系统异常终止,该怎么办?这会不会导致结构只被部分写入C# 在写入共享内存时,托管进程能否终止?,c#,.net,shared-memory,memory-mapped-files,cer,C#,.net,Shared Memory,Memory Mapped Files,Cer,我有几个(managed/.NET)进程通过一个环形缓冲区进行通信,该缓冲区通过MemoryMappedFile类保存在共享内存中(只是内存未映射文件)。我从SafeBuffer引用源知道,将结构写入该内存是由CER(受限执行区域)保护的,但如果写入过程在这样做时被操作系统异常终止,该怎么办?这会不会导致结构只被部分写入 struct MyStruct { public int A; public int B; public float C;
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行
基本上可以归结为这样一个问题:当执行CER块中的代码时(设置了Consistency.WillNotCorruptState标志),进程是否受到保护,不受异常终止的影响。是的,进程可以随时停止
SafeBuffer.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\u中的下一个服务员。这样,Windows会告诉您进程在获取锁时已死亡,您需要恢复上一个写入程序所做的更改 不,它是一个操作系统对象,它知道RAM页面已映射。如果操作系统也不能完成任务,您可能会丢失数据,例如断电。@Hans,我添加了一个代码示例来演示我的问题。对我来说,这不是关于丢失数据,而是关于写入数据的进程在写入过程中被终止时部分写入的数据。如果您不能确保Write()在程序崩溃/终止之前成功完成,那么您当然什么都不知道。Write()不是原子的。我想你会发现在MMF中指定一个字节来表示“忙写”很有用。在写入之前将其设置为1,在写入之后将其设置为0,现在您有了一个事实。为什么其他进程会在任何时候访问一个区域(大于64位)并假设一致性?听起来好像您有一个损坏的协议(或者需要存在的不存在的协议),MMF不一定对进程互操作有用。事实上,它是最不实用的用法之一。