windows进程通信-内存共享和信号量

0、共享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信。因为是通过内存操作实现通信,因此是一种最高效的数据交换方法。

调用 CreateFileMapping 创建一个内存文件映射对象:

HANDLE CreateFileMapping(
  HANDLE hFile,              // handle to file to map
  LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
                             // optional security attributes
  DWORD flProtect,           // protection for mapping object
  DWORD dwMaximumSizeHigh,   // high-order 32 bits of object size
  DWORD dwMaximumSizeLow,    // low-order 32 bits of object size
  LPCTSTR lpName             // name of file-mapping object
);
通过这个API函数 将创建一个内存映射文件的内核对象,用于映射文件到内存。与虚拟内存一样,内存映射文件可以用来保留一个地址空间的区域,并将物理存储器提交
给该区域。它们之间的差别是,物理存储器来自一个已经位于磁盘上的文件,而不是系统的页文件

hFile:用于标识你想要映射到进程地址空间中的文件句柄。该句柄可以通过调用C r e a t e F i l e函数返回。这里,我们并不需要一个实际的文件,所以,就不需要调用 CreateFile 创建一个文件, hFile 这个参数可以填写 INVALID_HANDLE_VALUE; 

lpFileMappingAttributes:参数是指向文件映射内核对象的 SECURITY_ATTRIBUTES结构的指针,通常传递的值是 N U L L;

flProtect:对内存映射文件的安全设置(PAGE_READONLY 以只读方式打开映射;PAGE_READWRITE 以可读、可写方式打开映射;PAGE_WRITECOPY 为写操作留下备份)

dwMaximumSizeHigh:文件映射的最大长度的高32位。

dwMaximumSizeLow:文件映射的最大长度的低32位。如这个参数和dwMaximumSizeHigh都是零,就用磁盘文件的实际长度。

lpName:指定文件映射对象的名字,别的进程就可以用这个名字去调用 OpenFileMapping 来打开这个 FileMapping 对象。
 
如果创建成功,返回创建的内存映射文件的句柄,如果已经存在,则也返回其句柄,但是调用 GetLastError()返回的错误码是:183(ERROR_ALREADY_EXISTS),如果创建失败,则返回NULL;

调用 MapViewOfFile 映射到当前进程的虚拟地址上:

如果调用CreateFileMapping成功,则调用MapViewOfFile函数,将内存映射文件映射到进程的虚拟地址中。

LPVOID MapViewOfFile(
  HANDLE hFileMappingObject,  // file-mapping object to map into 
                              // address space
  DWORD dwDesiredAccess,      // access mode
  DWORD dwFileOffsetHigh,     // high-order 32 bits of file offset
  DWORD dwFileOffsetLow,      // low-order 32 bits of file offset
  DWORD dwNumberOfBytesToMap  // number of bytes to map
);
 
hFileMappingObject:CreateFileMapping()返回的文件映像对象句柄。
dwDesiredAccess: 映射对象的文件数据的访问方式,而且同样要与CreateFileMapping()函数所设置的保护属性相匹配。
dwFileOffsetHigh: 表示文件映射起始偏移的高32位.
dwFileOffsetLow: 表示文件映射起始偏移的低32位.
dwNumberOfBytesToMap :文件中要映射的字节数。为0表示映射整个文件映射对象。

在接收进程中打开对应的内存映射对象:

在数据接收进程中,首先调用OpenFileMapping()函数打开一个命名的文件映射内核对象,得到相应的文件映射内核对象句柄hFileMapping;如果打开成功,则调用MapViewOfFile()函数映射对象的一个视图,将文件映射内核对象hFileMapping映射到当前应用程序的进程地址,进行读取操作。(当然,这里如果用CreateFileMapping也是可以获取对应的句柄)

HANDLE OpenFileMapping(
  DWORD dwDesiredAccess,  // access mode
  BOOL bInheritHandle,    // inherit flag
  LPCTSTR lpName          // pointer to name of file-mapping object
);
 
dwDesiredAccess:同MapViewOfFile函数的dwDesiredAccess参数
bInheritHandle :如这个函数返回的句柄能由当前进程启动的新进程继承,则这个参数为TRUE。
lpName :指定要打开的文件映射对象名称。

进行内存映射文件的读写:

一旦MapViewOfFile调用成功,就可以像读写本进程地址空间的内存区一样,进行内存的读写操作了。

//读操作:
if ( m_pViewOfFile  )
{
        // read text from memory-mapped file
        TCHAR s[dwMemoryFileSize];
        
        lstrcpy(s, (LPCTSTR) m_pViewOfFile);
}
//写操作:
if ( m_pViewOfFile )
 {
        TCHAR s[dwMemoryFileSize];
        m_edit_box.GetWindowText(s, dwMemoryFileSize);
            
        lstrcpy( (LPTSTR) m_pViewOfFile, s);
            
        // Notify all running instances that text was changed
        ::PostMessage(HWND_BROADCAST, 
            wm_Message,     
            (WPARAM) m_hWnd,
            0);    
}






1、Creating Named Shared Memory

To share data, multiple processes can use memory-mappedfiles that the system paging file stores.

FirstProcess

The first process creates the file mapping object bycalling the CreateFileMapping functionwith INVALID_HANDLE_VALUE and a name for the object. By usingthe PAGE_READWRITE flag, the process has read/write permissionto the memory through any file views that are created.

Then the process uses the file mapping object handle that CreateFileMapping returnsin a call to MapViewOfFile tocreate a view of the file in the process address space. The MapViewOfFile functionreturns a pointer to the file view, pBuf. The process then uses the CopyMemory functionto write a string to the view that can be accessed by other processes.

Prefixing the file mapping object names with"Global\" allows processes to communicate with each other even ifthey are in different terminal server sessions. This requires that the firstprocess must have the SeCreateGlobalPrivilege privilege.

When the process no longer needs access to the filemapping object, it should call the CloseHandle function.When all handles are closed, the system can free the section of the paging filethat the object uses.

first process

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>

#define BUF_SIZE 256
TCHAR szName[]=TEXT("Global\\MyFileMappingObject");
TCHAR szMsg[]=TEXT("Message from first process.");

int _tmain()
{
   HANDLE hMapFile;
   LPCTSTR pBuf;

   hMapFile = CreateFileMapping(
                 INVALID_HANDLE_VALUE,    // use paging file
                 NULL,                    // default security
                 PAGE_READWRITE,          // read/write access
                 0,                       // maximum object size (high-order DWORD)
                 BUF_SIZE,                // maximum object size (low-order DWORD)
                 szName);                 // name of mapping object

   if (hMapFile == NULL)
   {
      _tprintf(TEXT("Could not create file mapping object (%d).\n"),
             GetLastError());
      return 1;
   }
   pBuf = (LPTSTR) MapViewOfFile(hMapFile,   // handle to map object
                        FILE_MAP_ALL_ACCESS, // read/write permission
                        0,
                        0,
                        BUF_SIZE);

   if (pBuf == NULL)
   {
      _tprintf(TEXT("Could not map view of file (%d).\n"),
             GetLastError());

       CloseHandle(hMapFile);

      return 1;
   }


   CopyMemory((PVOID)pBuf, szMsg, (_tcslen(szMsg) * sizeof(TCHAR)));
    _getch();

   UnmapViewOfFile(pBuf);

   CloseHandle(hMapFile);

   return 0;
}

second process

A second process can access the string written to theshared memory by the first process by calling the OpenFileMapping functionspecifying the same name for the mapping object as the first process. Then itcan use the MapViewOfFile functionto obtain a pointer to the file view, pBuf. The process can display this string as it would anyother string. In this example, the message box displayed contains the message"Message from first process" that was written by the first process.

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#pragma comment(lib, "user32.lib")

#define BUF_SIZE 256
TCHAR szName[]=TEXT("Global\\MyFileMappingObject");

int _tmain()
{
   HANDLE hMapFile;
   LPCTSTR pBuf;

   hMapFile = OpenFileMapping(
                   FILE_MAP_ALL_ACCESS,   // read/write access
                   FALSE,                 // do not inherit the name
                   szName);               // name of mapping object

   if (hMapFile == NULL)
   {
      _tprintf(TEXT("Could not open file mapping object (%d).\n"),
             GetLastError());
      return 1;
   }

   pBuf = (LPTSTR) MapViewOfFile(hMapFile, // handle to map object
               FILE_MAP_ALL_ACCESS,  // read/write permission
               0,
               0,
               BUF_SIZE);

   if (pBuf == NULL)
   {
      _tprintf(TEXT("Could not map view of file (%d).\n"),
             GetLastError());

      CloseHandle(hMapFile);

      return 1;
   }

   MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);

   UnmapViewOfFile(pBuf);

   CloseHandle(hMapFile);

   return 0;
}
2、

程序包括一个客户端和一个服务端,服务端创建共享内存,客户端打开共享内存,两者通过两个事件互斥访问共享内存,实现一个小功能,就是服务端进程从控制台读入数据发送给客户端进程。

服务端:

#include "stdafx.h"  
#include <Windows.h>  
#include <iostream>  
using namespace std;  
  
int main()  
{  
    HANDLE hMutex           = NULL;  
    HANDLE hFileMapping     = NULL;  
    LPVOID lpShareMemory    = NULL;  
    HANDLE hServerWriteOver = NULL;  
    HANDLE hClientReadOver  = NULL;  
  
    //create share memory  
    hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE,  
        NULL,  
        PAGE_READWRITE,  
        0,  
        1024*1024,  
        L"ShareMemoryTest");  
    if (NULL == hFileMapping)  
    {  
        cout << "CreateFileMapping fail:" << GetLastError() << endl;  
        goto SERVER_SHARE_MEMORY_END;  
    }  
  
    lpShareMemory = MapViewOfFile(hFileMapping,  
        FILE_MAP_ALL_ACCESS,  
        0,  
        0,      //memory start address  
        0);     //all memory space  
    if (NULL == lpShareMemory)  
    {  
        cout << "MapViewOfFile" << GetLastError() << endl;  
        goto SERVER_SHARE_MEMORY_END;  
    }  
  
    //373  
    hMutex = CreateMutex(NULL, FALSE, L"SM_Mutex");  
    if (NULL == hMutex || ERROR_ALREADY_EXISTS == GetLastError())  
    {  
        cout << "CreateMutex" << GetLastError() << endl;  
        goto SERVER_SHARE_MEMORY_END;  
    }//多个线程互斥访问  
  
    //send data  
    hServerWriteOver = CreateEvent(NULL,  
        TRUE,  
        FALSE,  
        L"ServerWriteOver");  
    hClientReadOver = CreateEvent(NULL,  
        TRUE,  
        FALSE,  
        L"ClientReadOver");  
    if (NULL == hServerWriteOver ||  
        NULL == hClientReadOver)  
    {  
        cout << "CreateEvent" << GetLastError() << endl;  
        goto SERVER_SHARE_MEMORY_END;  
    }  
  
    char p = 0;  
    char* q = (char*)lpShareMemory;  
    do   
    {  
        p = getchar();  
        if (WaitForSingleObject(hClientReadOver, 5*1000) != WAIT_OBJECT_0)   
            goto SERVER_SHARE_MEMORY_END;  
        q[0] = p;  
        if (!ResetEvent(hClientReadOver)) goto SERVER_SHARE_MEMORY_END;//把指定的事件对象设置为无信号状态  
        if (!SetEvent(hServerWriteOver)) goto SERVER_SHARE_MEMORY_END;//把指定的事件对象设置为有信号状态  
    } while (p != '\n');  
  
SERVER_SHARE_MEMORY_END:  
    //release share memory  
    if (NULL != hServerWriteOver)   CloseHandle(hServerWriteOver);  
    if (NULL != hClientReadOver)    CloseHandle(hClientReadOver);  
    if (NULL != lpShareMemory)      UnmapViewOfFile(lpShareMemory);  
    if (NULL != hFileMapping)       CloseHandle(hFileMapping);  
    if (NULL != hMutex)             ReleaseMutex(hMutex);  
    return 0;  
}  
客户端

#include "stdafx.h"  
#include <Windows.h>  
#include <iostream>  
using namespace std;  
int main()  
{  
    HANDLE hMutex           = NULL;  
    HANDLE hFileMapping     = NULL;  
    LPVOID lpShareMemory    = NULL;  
    HANDLE hServerWriteOver = NULL;  
    HANDLE hClientReadOver  = NULL;  
  
    hMutex = OpenMutex(MUTEX_ALL_ACCESS,  
        FALSE,  
        L"SM_Mutex");  
    if (NULL == hMutex)  
    {  
        if (ERROR_FILE_NOT_FOUND == GetLastError())  
        {  
            cout << "OpenMutex fail: file not found!" << endl;  
            goto CLIENT_SHARE_MEMORY_END;  
        }  
        else  
        {  
            cout << "OpenMutex fail:" << GetLastError() << endl;  
            goto CLIENT_SHARE_MEMORY_END;  
        }  
    }  
  
    if (WaitForSingleObject(hMutex, 5000) != WAIT_OBJECT_0)//hMutex 一旦互斥对象处于有信号状态,则该函数返回  
    {  
        DWORD dwErr = GetLastError();  
        goto CLIENT_SHARE_MEMORY_END;  
    }  
  
    //open share memory  
    hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS,  
        FALSE,  
        L"ShareMemoryTest");  
    if (NULL == hFileMapping)  
    {  
        cout << "OpenFileMapping" << GetLastError() << endl;  
        goto CLIENT_SHARE_MEMORY_END;  
    }  
  
    lpShareMemory = MapViewOfFile(hFileMapping,  
        FILE_MAP_ALL_ACCESS,  
        0,  
        0,  
        0);  
    if (NULL == lpShareMemory)  
    {  
        cout << "MapViewOfFile" << GetLastError() << endl;  
        goto CLIENT_SHARE_MEMORY_END;  
    }  
  
    //read and write data  
    hServerWriteOver = CreateEvent(NULL,  
        TRUE,  
        FALSE,  
        L"ServerWriteOver");  
    hClientReadOver = CreateEvent(NULL,  
        TRUE,  
        FALSE,  
        L"ClientReadOver");  
    if (NULL == hServerWriteOver ||  
        NULL == hClientReadOver)  
    {  
        cout << "CreateEvent" << GetLastError() << endl;  
        goto CLIENT_SHARE_MEMORY_END;  
    }  
  
    char p = 0;  
    char* q = (char*)lpShareMemory;  
    do   
    {  
        if (!SetEvent(hClientReadOver))   
            goto CLIENT_SHARE_MEMORY_END;  
  
        if (WaitForSingleObject(hServerWriteOver, INFINITE) != WAIT_OBJECT_0)   
            goto CLIENT_SHARE_MEMORY_END;   
  
        p = q[0];  
        putchar(p);  
        if (!ResetEvent(hServerWriteOver))   
            goto CLIENT_SHARE_MEMORY_END;  
    } while (p != '\n');  
  
CLIENT_SHARE_MEMORY_END:  
    //release share memory  
    if (NULL != hServerWriteOver)   CloseHandle(hServerWriteOver);  
    if (NULL != hClientReadOver)    CloseHandle(hClientReadOver);  
    if (NULL != lpShareMemory)      UnmapViewOfFile(lpShareMemory);  
    if (NULL != hFileMapping)       CloseHandle(hFileMapping);  
    if (NULL != hMutex)             ReleaseMutex(hMutex);  
    return 0;  
}  







  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值