• Windows进程间通信之共享内存


    之前自己做的一个项目涉及到进程间通信问题,我采用的是SOCKET方式。面试的时候有问过为什么不采用其他方式。好吧,其实发现共享内存更方便一点。于是自己写了一下,并且做了个测试界面。


    程序启动会获得自身的窗口句柄,另外可以输入一个窗口句柄,用于进程间Windows消息通信。File Mapping Name实际上就是内核对象名,进程间依据这个来访问共享内存。

    Windows下的共享内存实际是用文件映射实现的,可以用CreateFileMapping创建一个内存文件映射对象,用于映射文件到内存。该函数返回的是File Mapping Object句柄

    CreateFileMappingA(
        __in     HANDLE hFile,
        __in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
        __in     DWORD flProtect,
        __in     DWORD dwMaximumSizeHigh,
        __in     DWORD dwMaximumSizeLow,
        __in_opt LPCSTR lpName
        );

    1)因为并不需要创建一个实际的文件,所以把hFile设置成为0xFFFFFFFF(INVALID_HANDLE_VALUE)就行了。

    2)Windows支持64位的文件,但一般内存不会超过4G也就是32位文件就够用了,所以上面的参数当中,dwMaximumSizeHigh为0,dwMaximumSizeLow设置为需要开辟的内存大小。

    3)lpName用于标示这段内存,进程间通过这个标示访问这段内存。


    接着调用MapViewOfFile()映射到当前进程的虚拟地址上。该函数如果调用成功,返回映射文件的开始地址。如果失败为NULL。

    MapViewOfFile(
        __in HANDLE hFileMappingObject,
        __in DWORD dwDesiredAccess,
        __in DWORD dwFileOffsetHigh,
        __in DWORD dwFileOffsetLow,
        __in SIZE_T dwNumberOfBytesToMap
        );


    1)hFileMappingObject就是刚才调用CreateFileMapping返回的句柄。

    2)dwDesiredAccess设置为FILE_MAP_ALL_ACCESS。

    3)dwNumberOfBytesToMap,文件中要映射的字节数,也就是这块共享内存的大小。


    我的程序是这么调用它的。

    int Cp1Dlg::MapFile()
    {
    	CString str;
    	m_edit7.GetWindowTextA(str);
    	if(str.GetLength() == 0)
    	{
    		AfxMessageBox("File Mapping Name can't be NULL");
    		return -1;
    	}
    	m_hMapFile = CreateFileMapping(
    		INVALID_HANDLE_VALUE,
    		NULL,
    		PAGE_READWRITE,
    		0,
    		BUF_SIZE,
    		str.GetBuffer());
    	if(m_hMapFile == NULL)
    	{
    		AfxMessageBox("CreateFileMapping failed!");
    		return 1;
    	}
    	m_pBuf = static_cast<LPTSTR>(MapViewOfFile(
    		m_hMapFile,
    		FILE_MAP_ALL_ACCESS,
    		0,
    		0,
    		BUF_SIZE));
    	if(m_pBuf == NULL)
    	{
    		AfxMessageBox("MapViewOfFile failed!");
    		CloseHandle(m_hMapFile);
    		return 1;
    	}
    	return 0;
    }


    接下来就可以对m_pBuf进行写数据或者读数据了。

    写数据:

    m_edit6.GetWindowTextA(str);
    memcpy((void*)m_pBuf, str.GetBuffer(), str.GetLength());

    读数据:

    LRESULT Cp1Dlg::OnMsg3(WPARAM wParam, LPARAM lParam){
    	CString str;
    	str.Format("R:\t%s", m_pBuf);
    	m_list2.AddString(str);
    	memset((void*)m_pBuf, 0, BUF_SIZE);//读完之后对这块内存进行清零
    	return 0;
    }

    读数据我采用的是消息处理函数。因为当一个进程对内存完数据之后,我会发送一个Windows消息通知另一进程,在其收到这条消息后就会调用函数读取数据。

    比起SOCKET,的确挺方便的。但是如果两个进程同时对这块内存进行写数据该怎么办呢?这就涉及到进程间同步技术了。不过这个我没有做。

    把资源打包上传了。



  • 相关阅读:
    7 -- Spring的基本用法 -- 11... 基于XML Schema的简化配置方式
    7 -- Spring的基本用法 -- 10... 获取其他Bean的属性值;获取Field值;获取任意方法的返回值
    Java 代码块:静态代码块、构造代码块、构造函数块
    MyBatis Like
    7 -- Spring的基本用法 -- 9...容器中Bean的生命周期
    my-small.ini、my-medium.ini、my-large.ini、my-huge.ini文件的作用
    java.lang.Class<T> -- 反射机制及动态代理
    7 -- Spring的基本用法 -- 8... 抽象Bean与子Bean;Bean继承与Java继承的区别;容器中的工厂Bean;获得Bean本身的id;强制初始化Bean
    Eclipse Maven 配置setting.xml 的镜像远程仓库
    7 -- Spring的基本用法 -- 7... 创建Bean的3种方式
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3076915.html
Copyright © 2020-2023  润新知