我有几个(托管/ .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行它基本上归结为在执行CER块中的代码(设置了Consistency.WillNotCorruptState标志)时是否保护进程免于异常终止的问题。
答案 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就会告诉您一个进程在锁定时已经死亡,您需要恢复上一个编写器所做的更改。