Windows Mobile使用Shared Memory(共享内存)进行IPC(进程间通信)的开发
背景
在Unix-like系统进行IPC(Inter-process communication)通信,Shared memory是效率最高的,我称之为IPC的王中王。
简介
本文讲述在Windows Mobile和Windows Embedded CE下如何使用Shared Memory(共享内存)进行IPC(进程间通信)。演示如何使用Shared Memory共享数据,使用Named Event唤醒其他进程和使用Named Mutex去为共享数据加锁。
主要IPC的方法
在Windows Mobile和Windows Embedded CE系统下,主要的IPC方法有以下几种。
方法 |
通知 |
数据存储 |
数据大小 |
Named events |
间接 |
N/A |
N/A |
Windows messages |
间接 |
在Message中 |
很小,只能传输Integer或者使用COPYDATASTRUCT 传输对象 |
Point-to-point message queues |
间接 |
在Message中 |
小型,存在boxing和unboxing问题 |
MSMQ |
直接 |
在Message中 |
小型,存在boxing和unboxing问题 |
TCP sockets |
直接 |
直接发送流(stream) |
中度 |
Memory mapped files |
N/A |
mapped file |
中度 |
Registry |
N/A |
注册表 |
中度 |
File system |
N/A |
文件 |
大型 |
Database |
N/A |
数据库 |
大型 |
WCF |
N/A |
WCF消息 |
中度 |
上述表格参考了Interprocess Communication with the .NET Compact Framework 1.0
关于上述的IPC的方法,没有那个最好,选择的时候需要根据具体需求来决定。这篇文章主要关注Named events和Shared Memory。 我之前也写过关于其他IPC方法的文章,可以参考如下:
Windows Message
.NET Compact Framework下的进程间通信之Windows Message
MSMQ
.NET Compact Framework下的进程间通信之MSMQ开发
Registry
.NET Compact Framework下注册表导出工具的开发
File System
Windows Mobile和Wince下使用TinyXML进行Native C++的开发
Database
.NET Compact Framework下SQL CE的使用 (实现了SqlCeHepler的封装SqlCeHepler的测试类,见.NET Compact Framework下的单元测试)
Windows Mobile下Native C++访问SqlCe的封装
SQL Server Express和SQL Server Compact的应用
.NET Campact Framework下SQL CE兼容性问题
Windows Mobile下访问Sqlite的Native C++封装
还有Point-to-point message queues, TCP sockets等等一部分主题没有写,如果有人希望我总结出来,请留言,我后续会补充进去。
Shared Memory的实现
实现的代码主要参考了OpenNETCF的Smart Device Framework。
三个关键的类
MemoryMappedFile用于封装共享内存,在Windows Embedded CE下的共享内存是一个Memory Mapped File,也就是一个内存映射文件,在所有进程的都可以访问的内存中映射文件,操作该共享内存就类似于磁盘物理文件。所以继承于Stream,通过流来读写。
NamedMutex是进程级别的锁,在Native C++一般使用CRITICAL_SECTION做锁,而在.NET Compact Framework会使用monitor,微软已经把monitor封装到lock关键字中了,注意这个lock不是函数,是C#语言内嵌关键字。lock和Monitor等价。
关于lock和CRITICAL_SECTION的使用请参考下面文章。
Windows Mobile使用.NET Compact Framework开发多线程程序
Windows Mobile使用Native C++开发多线程程序
那么,既然有了lock和CRITICAL_SECTION为什么还需要Mutex呢,从性能来说Mutex的效率比Monitor也就是lock要低,所以我一般会使用lock而不是Mutex,但是lock不能支持跨进程加锁,所以在这个case,我使用了Mutex。
.NET Compact Framework本身就提供了一个Mutex的类,可惜只是支持无名Mutex。Mutex分为命名Mutex和无名Mutex,无名的Mutex只能在同一个进程内部使用,不能跨进程使用,所以这里封装了个NamedMutex来支持命名Mutex,从而支持跨进程的锁操作。
EventWaitHandle是通知Event。.NET Compact Framework本身封装了AutoResetEvent和ManualResetEvent,但是他们都不支持跨进程,所以封装了EventWaitHandle来实现跨进程的Event通知。
SharedMemoryWriter
SharedMemoryWriter负责往共享内存写数据。
private void StartSharedMemoryWriting()
{
MemoryMappedFile mmf = MemoryMappedFile.CreateInMemoryMap("SharedMemoryBlock");
int i = 100;
while (started)
{
string s = "SharedMemory:" + i.ToString();
UpdateMessageList(s);
byte[] dataBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(s);
// Wait until it is safe to enter.
mutex.WaitOne();
try
{
mmf.Position = 0;
mmf.Write(dataBuffer, 0, dataBuffer.Length);
}
finally
{
// Release the Mutex.
mutex.ReleaseMutex();
}
// Raise the event
namedEvent.Set();
++i;
if (i > 999)
{
i = 100;
}
System.Threading.Thread.Sleep(500);
}
mmf.Close();
}
生成系统唯一命名的共享内存,在这个例子中使用了SharedMemoryBlock。每次写共享内存的时候都通过Named Mutex对该内存加锁。当写完毕后通过Named Event通知SharedMemoryReader(读共享内存)的进程。
SharedMemoryReader
SharedMemoryReader负责读取共享内存的数据。
private void StartSharedMemoryReading()
{
MemoryMappedFile mmf = MemoryMappedFile.CreateInMemoryMap("SharedMemoryBlock");
byte[] dataBuffer = new byte[1024];
while (started)
{
if (namedEvent.WaitOne())
{
if (!started)
{
break;
}
namedEvent.Reset();
// Wait until it is safe to enter.
if (mutex.WaitOne())
{
try
{
mmf.Position = 0;
mmf.Read(dataBuffer, 0, 50);
}
finally
{
// Release the Mutex.
mutex.ReleaseMutex();
}
}
string s = System.Text.ASCIIEncoding.ASCII.GetString(dataBuffer, 0, 50);
UpdateMessageList(s);
}
}
mmf.Close();
}
打开同样名字(SharedMemoryBlock)的共享内存,这个进程会挂起直到收到Named Event的消息,每次读取的时候都需要使用Named Mutex来加锁。
源代码:https://files.cnblogs.com/procoder/SharedMemoryDemo.rar
环境: Windows Mobile 5 PPC + .NET Compact Framework 2.0
出处:http://procoder.cnblogs.com
本作品由Jake Lin创作,采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。 任何转载必须保留完整文章,在显要地方显示署名以及原文链接。如您有任何疑问或者授权方面的协商,请给我留言。