C#使⽤共享内存实现进程间的通信
进程通信有多种⽅式,⽐如socket、管道、共享内存。c#直接提供了共享内存的相关库,但直接使⽤起来还是不太⽅便,需要使⽤Marshal处理内存对齐以及托管⾮托管转换的问题,本⽂提供⼀种,将上述操作包装,借助反射的⼿段,实现通过类和属性的⽅式使⽤共享内存。
⼀、共享内存对象
MemoryMappedFile是的共享内存对象,⼀般通过MemoryMappedFile.CreateNew的⽅式创建共享内存,最简单的创建⽅式是,传⼊名称及⼤⼩。
//申请共享内存
MemoryMappedFile mmf = MemoryMappedFile.CreateNew(name, size);
写共享内存,在指定位置,通过数组写⼊数据。
using (var accessor = mmf.CreateViewAccessor(0, Size))
{
accessor.WriteArray(field.Position, array, 0, array.Length);
}
读共享内存,在指定位置读取数据到数组。
using (var accessor = mmf.CreateViewAccessor(0, Size))
{
accessor.ReadArray(field.Position, buffer, 0, buffer.Length);
}
⼆、定义上层共享内存对象
1、共享内存对象
class SharedMemory : IDisposable
{
/
// <summary>
/// 共享内存名称(唯⼀标识)
鄙薄
/// </summary>
public string Name { private t; get; }
/// <summary>
/// ⼤⼩
/// </summary>
public long Size { private t; get; }
/// <summary>
/// 创建共享内存
/// </summary>
/
// <param name="name">共享内存名称(唯⼀标识)</param>
/// <param name="sharedMemoryFieldsMapping">映射实体对象</param>
/// <returns>共享内存对象</returns>
public static SharedMemory Create(string name, ISharedMemoryPropertiesMapping sharedMemoryFieldsMapping);
/// <summary>
/// 关闭共享内存
/// </summary>
public void Clo();
/// <summary>
/// 关闭共享内存
/// </summary>
public void Dispo();
}
2、映射实体接⼝
继承此接⼝的类即可以作为共享内存的映射数据。
//共享内存映射接⼝,实现此接⼝的对象其属性可以直接与共享内存映射。
//规则是,属性类型只⽀持结构体以及byte[]数组
//属性排列顺序即内存排列顺序
interface ISharedMemoryPropertiesMapping
{
event Action<object, SharedMemoryPropertyChangedEventArgs> PropertyChanged;
event Func<string, object> GetPropertyValue;
}
public class SharedMemoryPropertyChangedEventArgs
{
public object Value { t; get; }
public string FieldName { t; get; }
}
//内存映射接⼝简化实现
abstract class SharedMemoryFieldsMapping : ISharedMemoryPropertiesMapping
{
河北医科大学怎么样protected void NotifyFieldChanged(object value, [System.Runtime.CompilerServices.CallerMemberName] string filedName = "");
protected object NotifyGetFieldValue(object defalut, [System.Runtime.CompilerServices.CallerMemberName]string filedName = "");
public event Action<object, SharedMemoryPropertyChangedEventArgs> PropertyChanged;
public event Func<string, object> GetPropertyValue;
}
三、使⽤⽅法
通过上述⽅式实现的上层共享内存对象,使⽤共享内存将变得⾮常简单。只需如下步骤:
1、定义共享内存实体
继承SharedMemoryFieldsMapping,定义需要的属性,t调⽤NotifyFieldChanged传⼊value,get调⽤NotifyGetFieldValue传⼊属性类型的缺省值 ,如下所⽰:
class SharedData : SharedMemoryFieldsMapping
{
public double CurentTime{t{ NotifyFieldChanged(value);}get{return (double)NotifyGetFieldValue(double.NaN);} }
public double Duration { t { NotifyFieldChanged(value); } get { return (double)NotifyGetFieldValue(double.NaN); } }
public int IsPau { t { NotifyFieldChanged(value); } get { return (int)NotifyGetFieldValue(1); } }
public int IsMute { t { NotifyFieldChanged(value); } get { return (int)NotifyGetFieldValue(1); } }
public int Heartbeat { t { NotifyFieldChanged(value); } get { return (int)NotifyGetFieldValue(0); } }
public int Flag { t { NotifyFieldChanged(value); } get { return (int)NotifyGetFieldValue(0); } }
public int Length { t { NotifyFieldChanged(value); } get { return (int)NotifyGetFieldValue(0); } }
[SharedMemeory(Size = 1024)]
public byte[] Input { t { NotifyFieldChanged(value); } get { return (byte[])NotifyGetFieldValue(null); } }
[SharedMemeory(Size = 1024)]
public byte[] Output { t { NotifyFieldChanged(value); } get { return (byte[])NotifyGetFieldValue(null); } }
}
注:(1)、属性的类型必须是值类型即元类型或结构体,引⽤类型只⽀持数组且必须设置数长度。
(2)、属性排列顺序即内存排列顺序
(3)、当前版本内存对齐为1,在c++中的内存对齐需要设置为#pragma pack(1)
上述对象在c++程序中可以直接使⽤如下数据结构对应:
double CurentTime;//当前时间
double Duration;//总时长
int IsPau;
int IsMute;
int Heartbeat;//⼼跳
int Flag;
int Length;
char Input[1024];
char Output[1024];
}SharedData;
立刻说2、创建共享内存
初始化⼀个共享内存实体对象,然后调⽤SharedMemory.Create,传⼊共享内存的名称以及共享内存实体对象即创建完成,此后直接读写实体的属性即是在读写共享内存。
SharedData dataShared = new SharedData();
var sharedMemory = SharedMemory.Create(sharedName, dataShared);
3、销毁共享内存
使⽤完成后需要销毁共享内存,否则可能会⼀直存在操作系统中,就算进程退出,共享内存可能依然存在。
sharedMemory.Dispo();
四、使⽤实例
这⾥的实例只⽤了互斥锁来控制资源有序访问,真实使⽤场景⼀般是需要⽤条件变量或者信号量来做访问控制的。下⾯是具体代码:
1、⽗进程
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace testshared
{
class Program
{
//内存映射的实体属性排列顺序与内存排列直接相关
class SharedData : SharedMemoryFieldsMapping
{
public double CurentTime { t { NotifyFieldChanged(value); } get { return (double)NotifyGetFieldValue(double.NaN); } } public double Duration { t { NotifyFieldChanged(value); } get { return (double)NotifyGetFieldValue(double.NaN); } }
中考题public int IsPau { t { NotifyFieldChanged(value); } get { return (int)NotifyGetFieldValue(1); } }
public int IsMute { t { NotifyFieldChanged(value); } get { return (int)NotifyGetFieldValue(1); } }
public int Heartbeat { t { NotifyFieldChanged(value); } get { return (int)NotifyGetFieldValue(0); } }
public int Flag { t { NotifyFieldChanged(value); } get { return (int)NotifyGetFieldValue(0); } }
public int Length { t { NotifyFieldChanged(value); } get { return (int)NotifyGetFieldValue(0); } }
[SharedMemeory(Size = 1024)]
public byte[] Info { t { NotifyFieldChanged(value); } get { return (byte[])NotifyGetFieldValue(null); } }
}
static void Main(string[] args)
产品说明书范文
{
Console.WriteLine("⽗进程启动");
//创建共享内存
SharedData data = new SharedData();
var sharedMemory = SharedMemory.Create("testshared", data);
/
/创建互斥锁
Mutex mutex = new Mutex(fal,"testsharedMutex");
Console.WriteLine("⽗进程发送:hello word!");
//加锁写⼊消息
mutex.WaitOne();
data.Info= Encoding.ASCII.GetBytes("hello word!");
mutex.ReleaMutex();
//启动⼦进程并将互斥锁名称传⼊
var process = new Process();
process.StartInfo.FileName = "";
process.StartInfo.Arguments = "testsharedMutex";
西南位育中学
process.Start();
Thread.Sleep(2000);
Console.WriteLine("⽗进程发送:exit");
//加锁写⼊消息
mutex.WaitOne();
data.Info = Encoding.ASCII.GetBytes("exit\0");
mutex.ReleaMutex();
//等待⼦进⾏退出
process.WaitForExit();
//销毁共享内存及互斥锁
优雅女人
sharedMemory.Dispo();
mutex.Dispo();
Console.WriteLine("⽗进程退出");
}
}
}
2、⼦进程
#include <iostream>
#include<Windows.h>
typedef struct _Shared {
double CurentTime;//当前时间
double Duration;//总时长
查六级成绩
int IsPau;
int IsMute;
int Heartbeat;//⼼跳
int Flag;
int Length;
char Info[1024];
}Shared;
int main(int argc, char** argv)
{
if (argc < 2)
return -1;
printf("⼦进程启动\n");
//创建⽗进程的互斥锁
auto mtx = CreateMutexA(NULL, FALSE, argv[1]);
//打开共享内存
HANDLE hfile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, "testshared");
if (NULL == hfile)
{
MessageBoxA(0, "不能打开共享内存", "提⽰", MB_OK);
return -1;
}
//映射地址
Shared* shared;
shared = (Shared*)MapViewOfFile(hfile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(Shared)); //进⼊互斥锁并读取数据
WaitForSingleObject(mtx, INFINITE);
printf("⼦进程接收:%s\n", shared->Info);
ReleaMutex(mtx);
while (1)
{
Sleep(30);
//进⼊互斥锁并读取数据
WaitForSingleObject(mtx, INFINITE);satan
if (strcmp(shared->Info, "exit")==0)
{
printf("⼦进程接收:%s\n", shared->Info);
ReleaMutex(mtx);
break;
}
ReleaMutex(mtx);
}
//销毁资源
CloHandle(hfile);
CloHandle(mtx);
printf("⼦进程退出\n");
mmbreturn 0;
}
五、完整代码