1、前言
共享内存(Shared Memory)是一种高效的跨进程通信方式,尤其适用于同一台计算机上的进程之间的高速数据传输。与套接字相比,共享内存允许多个进程直接访问同一块内存区域,减少了数据传输的中间步骤,适合需要高性能和低延迟的场景。本文将介绍如何在 C# 和 C++ 之间通过共享内存实现跨进程通信,并附上完整的示例代码。
2、什么是共享内存?
共享内存是一种在操作系统中分配的内存区域,允许多个进程对该内存区域进行读写。不同于管道或套接字,数据不需要被复制到缓冲区中进行传输,而是直接由各个进程访问内存数据,从而提高了数据传输效率。
3、实现步骤
- C++ 进程:创建共享内存区域,将数据写入内存。
- C# 进程:打开该共享内存区域,从内存中读取数据。
4、示例代码
以下代码展示了一个 C++ 进程创建并写入共享内存,另一个 C# 进程读取该共享内存中的数据。
C++ 代码:创建并写入共享内存
使用 Windows API 创建共享内存,并将数据写入共享内存区域。
#include<windows.h>#include<iostream>#include<cstring>intmain(){constchar* sharedMemoryName ="Local\\MySharedMemory";constchar* message ="Hello from C++!";// 创建共享内存
HANDLE hMapFile =CreateFileMappingA(
INVALID_HANDLE_VALUE,NULL,
PAGE_READWRITE,0,256,
sharedMemoryName
);if(hMapFile ==NULL){
std::cerr <<"Could not create file mapping object: "<<GetLastError()<< std::endl;return1;}// 映射内存
LPVOID pBuf =MapViewOfFile(
hMapFile,
FILE_MAP_ALL_ACCESS,0,0,256);if(pBuf ==NULL){
std::cerr <<"Could not map view of file: "<<GetLastError()<< std::endl;CloseHandle(hMapFile);return1;}// 写入数据到共享内存CopyMemory((PVOID)pBuf, message,strlen(message)+1);
std::cout <<"Data written to shared memory: "<< message << std::endl;
std::cout <<"Press Enter to exit...";
std::cin.get();// 释放资源UnmapViewOfFile(pBuf);CloseHandle(hMapFile);return0;}
代码解析:
CreateFileMappingA
:创建共享内存对象。MapViewOfFile
:将共享内存映射到进程地址空间。CopyMemory
:将数据写入共享内存。UnmapViewOfFile
和CloseHandle
:释放内存映射并关闭句柄。
C# 代码:读取共享内存
在 C# 中使用
MemoryMappedFile
类打开并读取共享内存数据。
usingSystem;usingSystem.IO.MemoryMappedFiles;usingSystem.Text;classProgram{staticvoidMain(){conststring sharedMemoryName ="Local\\MySharedMemory";// 打开共享内存using(MemoryMappedFile mmf = MemoryMappedFile.OpenExisting(sharedMemoryName)){// 读取共享内存数据using(MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(0,256)){byte[] buffer =newbyte[256];
accessor.ReadArray(0, buffer,0, buffer.Length);// 将字节数组转换为字符串string message = Encoding.ASCII.GetString(buffer).TrimEnd('\0');
Console.WriteLine("Data read from shared memory: "+ message);}}}}
代码解析:
MemoryMappedFile.OpenExisting
:打开现有的共享内存对象。MemoryMappedViewAccessor
:创建内存视图以读取共享内存中的数据。ReadArray
:从共享内存中读取数据。Encoding.ASCII.GetString
:将字节数组转换为字符串。
5、运行步骤
- 编译并运行 C++ 程序,它将创建共享内存并写入数据。
- 运行 C# 程序,它将打开并读取共享内存中的数据。
运行结果:
- C++ 程序输出:
Data written to shared memory: Hello from C++!
- C# 程序输出:
Data read from shared memory: Hello from C++!
6、注意事项
- 命名空间一致性:确保共享内存名称一致,否则 C# 程序无法找到 C++ 程序创建的共享内存。
- 访问权限:共享内存的访问权限应当在 C++ 和 C# 之间保持一致。
- 数据格式:在多字节字符的处理上要确保编码一致,以免出现乱码。
7、应用场景
- 高性能数据传输:适用于大数据量、低延迟的应用场景,如视频处理、游戏引擎等。
- 跨进程数据共享:允许多个进程同时访问同一块数据,减少数据复制开销。
8、优缺点
- 优点: - 高速数据传输,适合大数据量传输场景。- 不需要数据序列化与反序列化,降低了性能开销。
- 缺点: - 只适用于同一台计算机上的进程通信。- 需要注意数据同步,避免多个进程同时写入导致的数据竞争。
9、总结
通过共享内存,C# 和 C++ 程序能够实现高效的跨进程通信,适用于高频、大数据量的数据传输需求。共享内存虽然具备较高的性能优势,但同时需要妥善管理访问权限和数据同步。
在下一篇文章中,我们将介绍 消息队列(Message Queues) 的实现方法,它更适合分布式系统中数据量不大但需要排队处理的场景。
版权归原作者 dotnet研习社 所有, 如有侵权,请联系我们删除。