一、背景
- 我有一个 C++进程A 与一个 C#进程B,我需要这两个进程进行通信;
- C#进程B 负责写入数据,C++ 进程A 负责读取数据;
- 管道在 C#进程B 中创建并写入,C++ 进程A 在获得管道句柄后再去读取。
二、代码
1. C# 端代码
public partial class MainWindow : Window
{
private bool create_memory_successful = false;
private readonly int shared_memory_size = 640 * 480 * 4;
private readonly string shared_memory_name = "shared_memory";
private readonly string shared_memory_mutex = "shared_memory_mutex";
private MemoryMappedFile shared_memory = null;
private MemoryMappedViewStream shared_stream = null;
private Mutex shared_mutex = null;
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
try
{
shared_memory = MemoryMappedFile.CreateOrOpen(shared_memory_name, shared_memory_size);
create_memory_successful = true;
Console.WriteLine("*** Create shared memory successful ***");
}
catch (Exception ex)
{
Console.WriteLine("*** Create shared memory error: " + ex.ToString() + " ***");
create_memory_successful = false;
}
if(create_memory_successful)
{
bool flag = false;
shared_mutex = new Mutex(true, shared_memory_mutex , out flag);
Console.WriteLine("*** Create mutex successful ***");
}
}
public void OnImageCaptured(USRawImage )
{
if (create_memory_successful && shared_mutex.WaitOne(10))
{
byte[] imageWidth = BitConverter.GetBytes(rawImage.PixelWidth);
byte[] imageHeight = BitConverter.GetBytes(rawImage.PixelHeight);
shared_stream = shared_memory.CreateViewStream(0, shared_memory_size);
if (shared_stream.CanWrite)
{
Console.WriteLine("Write data");
shared_stream.Write(imageWidth, 0, imageWidth.Length);
shared_stream.Write(imageHeight, 0, imageHeight.Length);
shared_stream.Dispose();
}
shared_mutex.ReleaseMutex();
}
}
protected override void OnClosed(EventArgs e)
{
shared_memory.Dispose();
while(!shared_mutex.WaitOne(10))
{
Console.WriteLine("Waiting mutex release");
Thread.Sleep(100);
}
shared_mutex.ReleaseMutex();
shared_mutex.Dispose();
}
}
2. C++端代码
#define sharedMemoryName L"shared_memory"
#define sharedMemoryMutex L"shared_memory_mutex"
HANDLE m_shareMutex;
void SharedMemoryThread()
{
HANDLE hMapFile;
while (1)
{
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, NULL, sharedMemoryName);
if (hMapFile == nullptr)
{
_cprintf("/* Waiting shared memory creation...... */\n");
}
else
{
break;
}
Sleep(1000);
}
_cprintf("/* Open shared memory successful! */ \n");
while (1)
{
if (hMapFile)
{
WaitForSingleObject(m_shareMutex, INFINITE);
LPVOID lpBase = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpBase)
{
unsigned char* pMemory = (unsigned char*)lpBase;
int imageWidth = 0, imageHeight = 0;
memcpy(&imageWidth, pMemory, 4);
memcpy(&imageHeight , pMemory + 4, 4);
UnmapViewOfFile(pMemory);
}
ReleaseMutex(m_shareMutex);
}
else
{
_cprintf("/* Shared memory handle error */\n");
break;
}
}
CloseHandle(hMapFile);
}
int main()
{
m_shareMutex = CreateMutex(NULL, false, sharedMemoryMutex);
std::thread sharedThread(SharedMemoryThread);
sharedThread.join();
}
3. C# 端关键函数
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
public static System.IO.MemoryMappedFiles.MemoryMappedFile CreateOrOpen(string mapName, long capacity);
public System.IO.MemoryMappedFiles.MemoryMappedViewStream CreateViewStream(long offset, long size);
4. C++端关键函数
HANDLE OpenFileMappingW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName);
LPVOID MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap
);
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);
DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);
总结
- 注意,我是先打开C++进程,然后再启动C#进程,然后在C#进程中创建共享内存并写入,然后在C++进程中获取共享内存句柄然后再读取。代码都是基于这个流程来考虑的。
- 当C#进程关闭时,C++进程仍会持续去读取共享内存中的数据。因为虽然是C#进程创建的共享内存,可是管理却是操作系统。所以即使C#进程关闭了,操作系统检测到内存句柄仍在C++进程使用,所以就不会回收,所以C++进程仍能持续读到内存。直到C++进程也关闭句柄之后,操作系统才会回收该内存。
- 进程间通信,加锁是非常重要的。请注意加锁的时序和释放顺序。