用内存映射文件实现多个程序间互斥运行!

本文介绍如何利用内存映射文件实现程序间的互斥运行,防止同一程序运行多个实例。通过具体示例展示了创建、映射和取消映射的过程,并讨论了在不同场景下的应用技巧。

      系统有时需要控制一些程序不能同时运行,也就是多个程序互斥运行,还包括禁止 同一程序 运行多个实例,这可以用 内存映射文件 来完成。内存映射文件 可以创建一个 没有和磁盘文件 相联系 的内存对象,通过名字在进程间共享,使用这个特性,来实现这个设计。以MFC自动生成的对话框程序为例,在程序初始化阶段,CWinApp派生类的InitInstance函数开始处,添加下面的代码:

 

当程序运行结束了,要记住调用CloseHandle(hMap)关闭这个对象句柄,可以在InitInstance函数最后return false之前调用。

其它非对话框类的程序,可以在各自的初始化和终止阶段添加类似代码。只是内存映射文件对象的句柄hMap可能在不同的函数中使用。那就要定义成全局的或是CWinApp派生类的成员变量了。

如果要考虑的更周到,使用 同样可以在进程间共享的 多线程同步对象类,如CMutex类对象,来控制对这个内存映射文件对象的读写访问。

 

 

CreateFileMapping 、MapViewOfFile、UnmapViewOfFile函数用法及示例
内存映射API函数CreateFileMapping创建一个有名的共享内存:
HANDLE CreateFileMapping(
HANDLE hFile, // 映射文件的句柄,//设为0xFFFFFFFF以创建一个进程间共享的对象
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全属性
DWORD flProtect, // 保护方式
DWORD dwMaximumSizeHigh, //对象的大小
DWORD dwMaximumSizeLow,
LPCTSTR lpName // 必须为映射文件命名
);

      与虚拟内存类似,保护方式可以是PAGE_READONLY或是PAGE_READWRITE。如果 多进程 都对同一 共享内存 进行写访问,则必须保持相互间同步。映射文件 还可以指定PAGE_WRITECOPY标志,可以保证其原始数据不会遭到破坏,同时允许其他进程在必要时自由的操作数据的拷贝。

      在创建映射文件对象后可以调用MapViewOfFile函数 映射到本进程 的 地址空间 内。下面说明创建一个名为MySharedMem的长度为4096字节的有名映射文件:

HANDLE hMySharedMapFile=CreateFileMapping((HANDLE)0xFFFFFFFF),NULL,PAGE_READWRITE,0,0x1000,"MySharedMem");
并映射缓存区视图(映射到本进程 的 地址空间 内):

LPSTR pszMySharedMapView=(LPSTR)MapViewOfFile(hMySharedMapFile,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);

其他 进程 访问共享对象,需要获得对象名并调用OpenFileMapping函数。
HANDLE hMySharedMapFile=OpenFileMapping(FILE_MAP_WRITE,FALSE,"MySharedMem");

      一旦其他进程获得映射对象的句柄,可以象创建进程那样调用MapViewOfFile函数来映射对象视图。用户可以使用该对象视图来进行数据读写操作,以达到数据通讯的目的。

当用户进程结束使用 共享内存 后,调用UnmapViewOfFile函数以取消 其地址空间内 的 视图:
if (!UnmapViewOfFile(pszMySharedMapView))
{

AfxMessageBox("could not unmap view of file");

}

 

以下是一个示例程序:

 


hMap = CreateFileMapping(&HFFFFFFFF, Security, PAGE_READWRITE, 0, dataLen, mapFileName)
Mapdress=MapViewOfFile(&&&)
UnmapViewOfFile(Mapdress)(成功执行了)
每次都CloseHandle(hMap)(返回值1成功了)
循环完
--------------------------------------------------------------------
【homezj】:
hMap增加好象不是你的问题所在呀,CloseHandle后,再CreateFileMapping,返回的hMap不相同很正常,它是系统自动分配的。
Security结构中有一个继承成员,设为非零时,当前线程就可以保留同一映射的handle,这个结构你指定了吗?注意,结构长度要指定正确才有效。
----------------------------------------------------------
【S1010070】:
With Security '安全对象
.nLength = Len(Security)
.lpSecurityDescriptor = 0
.bInheritHandle = 1 ' Doesn't really matter
End With
但是我试验过,当hMap的值只要超过60000000之后,程序就会出现内存不能为写的错误
----------------------------------------------------------
【homezj】:
也许是磁盘缓冲的延时,以前听过Map文件,不是实时释放的说法。还有,你这个Map是用于什么目的,是进程间交换数据吗?其它程序有没有对它的操作?mapFileName是不是只用统一的一个名称?这东西我不熟悉,只是觉得CreateFileMapping这样频繁使用不太正常。

这是题外话了,内存映射文件的主要目的是在频繁交换数据时减少IO操作,你这样建了又放,而且不断反复,IO读写不但没少反而可能会增多,因为每次建放映射将是对整个文件长度的一次IO读写,比直接在磁盘上局部读写数据量还大。若非要这样做,你不如,不要映射,直接用磁盘文件算了。

可能MS也是没想到会出现这种用法,所以没考虑缓存会影响实时更新,或干脆就没打算支持这种用法。

我建议,CreateFileMapping是不是可以只用一次,保留handle,在定时器中使用。当然MapViewOfFile等可能也只需用一次,因不了解你的目的,请自己酌情考虑。
----------------------------------------------------------
【S1010070】:
首先谢谢你的分析,
这个程序的主要目的是实时的监视数据,当数据达到规定值执行某个动作,当然数据是来自另一个程序,当时就是从内存映射提取数据了,我把把文件结果填充好以后,放入指定文件名的内存映射文件,然后SendMessage令一个程序,它来填充数据,我得到数据后UnmapViewOfFile(Mapdress)-----CloseHandle(hMap)
 你的意思我明白,但是软件结构就要改动很大,很麻烦了,这个软件又着急用,不知这位仁兄有何妙解?
----------------------------------------------------------
【homezj】:
是交换数据,我想按理mapFileName是统一的,也就是说只须一个进程去创建映射文件,而且CreateFileMapping只须在程序启动时执行一次,另一进程可用OpenFileMapping获取handle或本进程用DuplicateHandle复制一个handle传给它,每次Timer事件也不必CloseHandle,最后退出时别忘就行了。

map与unmap在timer中执行。这样可保证只建一个映射文件,我想改动起来,不会难吧?

不断Create并Close,对内存映射文件可能不适用,若用原来的方案,实在想不出解决办法。因为其用法本身可能就不对!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值