Linux下.NET Core/Mono进程共享内存IPC报错问题咨询
Linux单板机上.NET Core/Mono进程间通信问题解答
一、共享内存跨进程找不到的原因及解决办法
你遇到的System.IO.FileNotFoundException本质是Linux下.NET对共享内存的实现逻辑和Windows不同:.NET的MemoryMappedFile在Linux上实际是通过/dev/shm(tmpfs挂载的内存文件系统)中的文件实现的,跨进程访问失败通常是以下原因:
- 命名路径问题:如果创建共享内存时只用了相对名称(比如
"my_shm"),.NET会在当前进程的工作目录或默认临时路径创建文件,两个进程的工作目录不同就会找不到。 - 权限不匹配:创建共享内存的进程用户和客户端进程用户不同,导致客户端没有权限访问
/dev/shm下的对应文件。 - Mono与.NET Core的实现差异:Mono在Linux下对共享内存的命名解析逻辑和.NET Core略有区别,容易出现路径不匹配。
解决步骤:
- 强制使用绝对路径:创建/打开共享内存时指定
/dev/shm下的绝对路径,确保两个进程指向同一个资源:
服务端代码:
客户端代码:using System.IO.MemoryMappedFiles; using System.Text; // 创建1MB大小的共享内存,指定绝对路径 using var mmf = MemoryMappedFile.CreateOrOpen("/dev/shm/sbc_ipc_shm", 1024 * 1024); // 写入数据示例 using var accessor = mmf.CreateViewAccessor(); var data = "Hello from Server"u8.ToArray(); accessor.Write(0, data, 0, data.Length);using System.IO.MemoryMappedFiles; using System.Text; // 打开同一个绝对路径的共享内存 using var mmf = MemoryMappedFile.OpenExisting("/dev/shm/sbc_ipc_shm"); // 读取数据示例 using var accessor = mmf.CreateViewAccessor(); var buffer = new byte[20]; accessor.Read(0, buffer, 0, buffer.Length); Console.WriteLine(Encoding.UTF8.GetString(buffer).Trim('\0')); - 统一进程权限:两个进程使用同一个用户运行,或者创建共享内存后手动调整文件权限(比如在服务端执行
chmod 666 /dev/shm/sbc_ipc_shm)。 - 兼容Mono环境:如果用Mono,尽量避免使用
MemoryMappedFileOptions中的平台特定参数,保持代码简洁通用。
二、封装C++工具的可行性
完全可以通过封装C++原生API实现高性能IPC,甚至在极端场景下比.NET的共享内存抽象性能更优:
实现思路:
- 直接调用Linux原生共享内存API:用
shmget/shmat或者mmap直接映射/dev/shm中的文件,绕开.NET的抽象层,减少额外开销。 - 通过P/Invoke让.NET调用:将C++写的共享内存操作逻辑编译成动态链接库(.so),然后在.NET代码中用
[DllImport]调用。 - 同步机制配套:用Linux原生的信号量(
sem_t)、事件fd(eventfd)实现进程间同步,避免轮询浪费CPU。
注意点:
- 封装时要处理好内存的创建、映射、释放逻辑,避免内存泄漏或资源残留。
- 同步机制要确保线程安全,防止多个进程同时读写共享内存导致数据错乱。
三、额外的高性能IPC建议
如果共享内存的同步逻辑过于复杂,也可以尝试Unix域套接字:
- Unix域套接字是Linux本地IPC的高性能选项,开销远低于回环TCP,支持字节流和数据报模式。
- .NET Core 3.0+已经原生支持Unix域套接字,代码和TCP套接字类似,只需绑定到文件系统路径(比如
/tmp/sbc_ipc_socket)即可。
内容的提问来源于stack exchange,提问作者Pavel Kudrna
相关产品推荐
相关产品推荐

