写在前面的话
最近项目涉及到了共享内存的通信,相互之间传递结构体中的数据,所以记录一下。本篇会介绍共享内存是什么,将数据封装成一个结构体,之后通过共享内存来进行进程中的通信,代码也会附在后面。也是借鉴了很多别的大佬写的,只是在这里就不一一贴出链接了。都能搜到。
一、共享内存的介绍
1.1共享内存是什么?
共享内存是进程间通信的一种方式,这里先插句话,我们用thread打开的是线程,一个程序是一个进程,但是一个程序可以开很多线程。所以共享内存是不同程序之间的互相通信。
共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内存连接到他们自己的地址空间中,所有的进程都可以访问共享内存中的地址。如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。
特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取,所以我们通常需要用其他的机制来同步对共享内存的访问,例如信号量。
在Windows操作系统下,任何一个进程不允许读取、写入或是修改另一个进程的数据(包括变量、对象和内存分配等),但是在某个进程内创建的文件映射对象的视图却能够为多个其他进程所映射,这些进程共享的是物理存储器的同一个页面。
因此,当一个进程将数据写入此共享文件映射对象的视图时,其他进程可以立即获取数据变更情况。
1.2 共享内存通信原理
如上图所示:
每一段程序都有自己得控制块PCB,然后有自己地址空间Addr Space,然后有一个与之对应得页表。负责将进程得虚拟地址与物理地址进行映射,通过内存管理单元MMU进行管理。两个不同的虚拟地址通过页表映射到物理空间的同一区域,它们所指向的这块区域即共享内存。
1.3 共享内存在C#中代码
整了一个Class,我觉得行
简单来说共享内存从创建到回收都是以下几个主要函数
- 创建共享内存——CreateFileMapping
- 打开共享内存——OpenFileMapping
- 共享内心映射——MapViewOfFile
- 内存释放函数——UnmapViewOfFile
- 呼叫线程最后返回的错误代码——GetLastError
- 关闭线程句柄——CloseHandle
- 将共享内存数据读到结构体——Marshal.PtrToStructure
- 将结构体中的数据写入共享内存——Marshal.StructureToPtr
using System.Runtime.InteropServices;//非托管代码交互,能够把非托管代码转化为托管代码
class ShareMemory
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr CreateFileMapping(int hFile, IntPtr lpAttributes, uint flProtect, uint dwMaxSizeHi, uint dwMaxSizeLow, string lpName);
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr OpenFileMapping(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, string lpName);
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr MapViewOfFile(IntPtr hFileMapping, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool UnmapViewOfFile(