zoukankan      html  css  js  c++  java
  • Windows进程通信(IPC)之共享内存

    前言:我们知道windows os上有很多的api,编程语言对os进行操作,无论什么语言,最终都是通过windows api 的。

    在windows编程中,有个概念是句柄,句柄指向资源(一切可以利用的物理的逻辑的资源),其中文件操作,可以将文件映射到内存,此处的文件是广义的文件,可以指内存对象,邮件槽等。

    在windows中创建一个指向文件的虚拟内存,然后多个进程创建各个进程对这块内存的映射,通过访问各个进程的映射内存对这块虚拟内存进行访问,是共享内存实现的原理。

    下图很好的标明了整个原理。

     一、相关的API函数

    内存映射API函数CreateFileMapping创建一个有名的共享内存:

    HANDLE CreateFileMapping(
    HANDLE hFile,                         // 映射文件的句柄,设为0xFFFFFFFF以创建一个进程间共享的对象
    LPSECURITY_ATTRIBUTES lpFileMappingAttributes,   // 安全属性
    DWORD flProtect,                                                                   // 保护方式
    DWORD dwMaximumSizeHigh,                                           //对象的大小 
    DWORD dwMaximumSizeLow, 
    LPCTSTR lpName                                                                 // 必须为映射文件命名
    );

    HANDLE CreateFileMapping(
    HANDLE hFile, //物理文件句柄
    LPSECURITY_ATTRIBUTES lpAttributes, //安全设置
    DWORD flProtect, //保护设置
    DWORD dwMaximumSizeHigh, //高位文件大小
    DWORD dwMaximumSizeLow, //低位文件大小
    LPCTSTR lpName //共享内存名称
    );
    hFile 指定欲在其中创建映射的一个文件句柄。INVALID_HANDLE_VALUE,即0xFFFFFFFF表示在页面文件中创建一个可共享映射文件。
    lpAttributes 它指明返回的句柄是否可以被子进程所继承,指定一个安全对象,在创建文件映射时使用。如果为NULL(用ByVal As Long传递零),表示使用默认安全对象
    flProtect 有以下几种方式:
    PAGE_READONLY 以只读方式打开映射
    PAGE_READWRITE 以可读、可写方式打开映射
    PAGE_WRITECOPY 为写操作留下备份也可组合使用下述一个或多个常数:
    SEC_COMMIT 为文件映射一个小节中的所有页分配内存
    SEC_IMAGE 文件是个可执行文件
    SEC_RESERVE 为没有分配实际内存的一个小节保留虚拟内存空间
    dwMaximumSizeHigh 文件映射的最大长度的高32位
    dwMaximumSizeLow 文件映射的最大长度的低32位。如这个参数和dwMaximumSizeHigh都是零,就用磁盘文件的实际长度。
    lpName 指定文件映射对象的名字。如存在这个名字的一个映射,函数就会打开它。用vbNullString可以创建一个无名的文件映射。

    LPVOID WINAPI MapViewOfFile( //将一个文件映射对象映射到当前应用程序的地址空间。
      __in HANDLE hFileMappingObject,
      __in DWORD dwDesiredAccess,
      __in DWORD dwFileOffsetHigh,
      __in DWORD dwFileOffsetLow,
      __in SIZE_T dwNumberOfBytesToMap
      );
    hFileMappingObject 为CreateFileMapping返回的文件映像对象句柄。
    dwDesiredAccess 映射对象的文件数据的访问方式,而且同样要与CreateFileMapping()函数所设置的保护属性相匹配。
    可取以下值:
    FILE_MAP_ALL_ACCESS 等价于CreateFileMapping的 FILE_MAP_WRITE|FILE_MAP_READ.文件映射对象被创建时必须指定PAGE_READWRITE 选项.
    FILE_MAP_COPY 可以读取和写入文件.写入操作会导致系统为该页面创建一份副本.在调用 CreateFileMapping时 必须 传入PAGE_WRITECOPY保护属性.
    FILE_MAP_EXECUTE 可以将文件中的数据在调用CreateFileMapping时可以传入PAGE_EXECUTE_READWRITE或PAGE_EXECUTE_READ保护属性.
    FILE_MAP_READ 可以读取文件.在调用CreateFileMapping时可以传入PAGE_READONLY或PAGE_READWRITE保护属性.
    FILE_MAP_WRITE 可以读取和写入文件.在调用CreateFileMapping时必须传入PAGE_READWRITE保护属性.
    dwFileOffsetHigh 表示文件映射起始偏移的高32位.
    dwFileOffsetLow 表示文件映射起始偏移的低32位.(64KB对齐不是必须的)
    dwNumberOfBytes 指定映射文件的字节数.

    三、写端的实现

    #include <iostream>
    #include <windows.h>
    #include <string.h>
    #include <cstring>
    #include <istream>
    using namespace std;
    
    int main()
    {
        unsigned long buff_size = 1024 * 5;
    
        PVOID pBuff=NULL;
    
        HANDLE hFile = CreateFile(L"shared_memory",    //如果不映射到物理磁盘上,可以不用创建
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            NULL,
            OPEN_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            NULL);
    
        if (hFile==INVALID_HANDLE_VALUE)
        {
            cout << "create file error." << endl;
        }
    
        HANDLE hFile_mapping = CreateFileMapping(
            INVALID_HANDLE_VALUE,                  // 如果需要创建,而不是内存对象,可以传入hFile
            NULL,
            PAGE_READWRITE,
            0,
            buff_size,
            L"shared_memory");
    
        if (NULL != hFile_mapping)
        pBuff = MapViewOfFile(
            hFile_mapping,
            FILE_MAP_ALL_ACCESS,
            0,
            0,
            buff_size
        );
    
        char str[1024];
    
        while (true)
        {
            cout << "please enter data ."exit" end app" << endl;
            cin.getline(str,1024);
            if (str!="exit")
            {
                if (NULL != pBuff)
                    memcpy(pBuff, str, 1024);
            }
            else if (str == "exit")
            {
                break;
            }
    
        }
    
        if (NULL != pBuff)
            FlushViewOfFile(pBuff, buff_size);
    
        cout << "finish write, wait ..." << endl;
        Sleep(20000);
    
        if (NULL!=pBuff)
            UnmapViewOfFile(pBuff);
    
        if (NULL != hFile_mapping)
            CloseHandle(hFile_mapping);
    
        if (NULL != hFile)
            CloseHandle(hFile);
    
    }

    四、读端的实现

    #include <iostream>
    #include <windows.h>
    using namespace std;
    
    int main()
    {
        const unsigned long buff_size = 1024*5;
        LPVOID pBuff = NULL;
    
        HANDLE handle_file_mapping = OpenFileMapping(
            FILE_MAP_ALL_ACCESS,
            NULL,
            L"shared_memory");
    
        if (NULL!= handle_file_mapping)
            pBuff = MapViewOfFile(
                handle_file_mapping,
            FILE_MAP_ALL_ACCESS,
            0,
            0,
            0);
    
        if (handle_file_mapping==NULL|| pBuff==NULL)
        {
            cout << "create shared memory faild,please waitting the memory created and exect the app again!" << endl
                 <<"enter any key to  exit the app!";
            string temp;
            cin >> temp;
            return 0;
        }
    
        string str;
    
        while (true)
        {
            cout << "enter "yes" receive data, or enter "exit" " << endl;
            cin >> str;
            if (str=="yes")
            {
                char* share_buffer = (char*)pBuff;
                cout << share_buffer << endl;
            }
            else if (str == "exit")
            {
                break;
            }
    
        }
    
        if (NULL!= pBuff)
            UnmapViewOfFile(pBuff);
        if (NULL != handle_file_mapping)
            CloseHandle(handle_file_mapping);
        return 0;
    }

    五、结果如下

  • 相关阅读:
    Qt Create or VS 2015 使用 Opencv330 相机静态库链接错误如何解决?
    Qt create 如何构建 ActiveX 控件?
    VB 如何调用 c++ DLL?
    Opencv 330 如何裁剪图片中大的目标?
    Opencv 330 如何進行圖像的旋轉?
    Qt 开发 MS VC 控件终极篇
    Qt 5.9.4 如何静态编译和部署?
    图片理论基础
    iOS平台设置系统状态栏(通知栏、顶部状态栏)样式背景颜色或透明
    jQuery基础
  • 原文地址:https://www.cnblogs.com/xietianjiao/p/13657031.html
Copyright © 2011-2022 走看看