Windows進程通訊 -- 共享內存

享內存的方式原理就是將一份物理內存映射到不一樣進程各自的虛擬地址空間上,這樣每一個進程均可以讀取同一份數據,從而實現進程通訊。由於是經過內存操做實現通訊,所以是一種最高效的數據交換方法。安全

共享內存在 Windows 中是用 FileMapping 實現的,從具體的實現方法上看主要經過如下幾步來實現:app

一、調用 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函數 將建立一個內存映射文件的內核對象,用於映射文件到內存。與虛擬內存同樣,內存映射文件能夠用來保留一個地址空間的區域,並將物理存儲器提交
給該區域。它們之間的差異是,物理存儲器來自一個已經位於磁盤上的文件,而不是系統的頁文件。spa

複製代碼
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函數,將內存映射文件映射到進程的虛擬地址中;code

複製代碼
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也是能夠獲取對應的句柄)blog

複製代碼
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調用成功,就能夠像讀寫本進程地址空間的內存區同樣,進行內存的讀寫操做了。進程

複製代碼
//讀操做:

// 打開成功,映射對象的一個視圖,獲得指向共享內存的指針,顯示出裏面的數據
pBuffer = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pBuffer)
{
cout << ((CThostFtdcDepthMarketDataField *)pBuffer)->LastPrice << endl;
//cout << "讀取共享內存數據:" << ((CThostFtdcDepthMarketDataField *)pBuffer)->LastPrice << endl;
}
else
{
cout << "打開共享數據失敗!" << endl;
}

 

//寫操做:

// 映射對象的一個視圖,獲得指向共享內存的指針,設置裏面的數據
pBuffer = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pBuffer)
{
memcpy((CThostFtdcDepthMarketDataField*)pBuffer, DepthMarketData, sizeof(CThostFtdcDepthMarketDataField));
//cout << "寫入共享內存數據:" << ((CThostFtdcDepthMarketDataField *)pBuffer)->LastPrice << endl;
}
else
{
cout << "打開共享數據失敗!" << endl;
}

複製代碼

五、清理內核對象

在用完後,要取消本進程地址空間的映射,並釋放內存映射對象。

    //取消本進程地址空間的映射;   
    UnmapViewOfFile(pLocalMem);  
      
    pLocalMem=NULL;   
    //關閉文件映射內核文件  
    CloseHandle(hFileMapping);
相關文章
相關標籤/搜索