You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#原生MemoryMappedFile无法跨进程读取映射内存,Win32方法正常

问题描述

我有一个持续运行循环的任务线程,通过内存映射文件执行读取操作。当其他应用向该内存映射文件写入数据时,使用Win32内存映射文件方法的线程可以正常读取到数据,但使用C#原生MemoryMappedFile方法的线程却无法读取到这些数据。

可正常工作的Win32实现代码

IntPtr 
    _iFileMappingHandle,
    _iFileMapStartAddress;

_iFileMappingHandle = Win32.CreateFileMapping(Win32.InvalidFileHandle, 0,
                                             Win32.FileProtection.ReadWrite,
                                             0, (uint)Size, Name);
_iFileMapStartAddress = Win32.MapViewOfFile(_iFileMappingHandle,
                                           Win32.FileRights.ReadWrite, 0, 0, 0);
var autoReset = new EventWaitHandle(true, EventResetMode.AutoReset, LockName);
if (autoReset.WaitOne(5000))
{
    byte[] bTemp = new byte[Size];
    
    Marshal.Copy(_iFileMapStartAddress, bTemp, 0, 512);

无法正常读取的C#原生实现代码

var mmf = MemoryMappedFile.CreateOrOpen(Name
             , Size
             , MemoryMappedFileAccess.ReadWrite);

var viewSteam = mmf.CreateViewStream(0, Size);
var autoReset = new EventWaitHandle(true, EventResetMode.AutoReset, LockName);
while (!cancellationToken.IsCancellationRequested)
{
    if (autoReset.WaitOne(5000))
    {
        byte[] bTemp = new byte[Size];
        viewSteam.Read(bTemp, 0, Size);
问题原因及解决方法

核心问题在于**ViewStream的读取位置未重置**:第一次调用Read后,流的位置指针会停在读取完成的位置,后续Read会从该位置开始,而非内存映射的起始地址;而Win32的Marshal.Copy是直接从映射内存的起始地址拷贝,不存在位置指针问题。

解决方法一:重置流的读取位置

在每次调用Read前,将流的位置设为0,确保从内存映射的起始处读取:

if (autoReset.WaitOne(5000))
{
    byte[] bTemp = new byte[Size];
    viewSteam.Position = 0; // 重置读取位置到起始点
    viewSteam.Read(bTemp, 0, Size);
}

解决方法二:使用MemoryMappedViewAccessor替代ViewStream

MemoryMappedViewAccessor提供了更接近Win32方式的直接内存访问,无需处理流的位置问题:

var mmf = MemoryMappedFile.CreateOrOpen(Name, Size, MemoryMappedFileAccess.ReadWrite);
using var accessor = mmf.CreateViewAccessor(0, Size);
var autoReset = new EventWaitHandle(true, EventResetMode.AutoReset, LockName);

while (!cancellationToken.IsCancellationRequested)
{
    if (autoReset.WaitOne(5000))
    {
        byte[] bTemp = new byte[Size];
        accessor.ReadArray(0, bTemp, 0, Size);
    }
}

额外注意事项

  • 跨进程访问时,内存映射文件的名称、大小必须完全一致,否则会创建独立的映射对象。
  • 同步用的EventWaitHandle名称需保证唯一性,避免与系统中其他对象冲突。

内容的提问来源于stack exchange,提问作者steve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 02:23:33