1. 程式人生 > >Windows進程間共享內存通信實例

Windows進程間共享內存通信實例

eof mes article 利用 p s 操作系統 操作 soft cnblogs

Windows進程間共享內存通信實例

抄抄補補整出來

采用內存映射文件實現WIN32進程間的通訊:Windows中的內存映射文件的機制為我們高效地操作文件提供了一種途徑,它允許我們在WIN32進程中保留一段內存區域,把硬盤或頁文件上的目標文件映射到這段虛擬內存中。註意:在程序實現中必須考慮各進程之間的同步問題。

在Windows操作系統下,任何一個進程不允許讀取、寫入或是修改另一個進程的數據(包括變量、對象和內存分配等),但是在某個進程內創建的文件映射對象的視圖卻能夠為多個其他進程所映射,這些進程共享的是物理存儲器的同一個頁面。

因此,當一個進程將數據寫入此共享文件映射對象的視圖時,其他進程可以立即獲取數據變更情況。

為了進一步提高數據交換的速度,還可以采用由系統頁文件支持的內存映射文件而直接在內存區域使用,

顯然這種共享內存的方式是完全可以滿足在進程間進行大數據量數據快速傳輸任務要求的。


具體實現步驟如下: (http://www.jb51.net/article/52306.htm)

1、在服務器端進程中調用內存映射API函數CreateFileMapping創建一個有名字標識的共享內存;

函數CreateFileMapping原型如下:

2、在創建文件映射對象後,服務器端進程調用MapViewOfFile函數映射到本進程的地址空間內;

3、客戶端進程訪問共享內存對象,需要通過內存對象名調用OpenFileMapping函數,以獲得共享內存對象的句柄

4、如果客戶端進程獲得共享內存對象的句柄成功,則調用MapViewOfFile函數來映射對象視圖。用戶可以使用該對象視圖來進行數據讀寫操作,以達到數據通訊的目的。

5、當用戶進程結束使用共享內存後,調用UnmapViewOfFile函數以取消其地址空間內的視圖:

FileMapping用於將存在於磁盤的文件放進一個進程的虛擬地址空間,並在該進程的虛擬地址空間中產生一個區域用於“存放”該文件,這個空間就叫做File View(存放在進程的虛擬內存中),系統並同時產生一個File Mapping Object(存放於物理內存中)用於維持這種映射關系,這樣當多個進程需要讀寫那個文件的數據時,它們的File View其實對應的都是同一個File Mapping Object,這樣做可節省內存和保持數據的同步性,並達到數據共享的目的。

內存映射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");
任何可以獲得的物理文件句柄, 如果你需要創建一個物理文件無關的內存映射也無妨, 將它設置成為 0xFFFFFFFF(INVALID_HANDLE_VALUE)就可以了.


並映射緩存區視圖:
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");

}

要將文件中的數據映射到進程的虛擬內存中,你必須創建一個文件的視圖。
MapViewOfFile和MapViewOfFileEx函數使用CreateFileMapping返回的文件映射對象句柄來在進程的虛擬地址空間裏建立文件的視圖,或者文件的某個部分。如果這些函數指定的權限標誌和CreateFileMapping中的權限標誌不一致,則會執行失敗。
MapViewOfFile函數返回一個指向文件視圖的指針。利用MapViewOfFile中聲明的地址指針,程序就可以從文件中讀以及向文件中寫入數據。向文件視圖中寫入數據會導致文件映射對象改變。真正將數據寫入到磁盤上的文件,由系統負責處理。數據並不是馬上就別寫到磁盤上,很多文件的輸入輸出都被緩存起來,以改善系統的性能。程序可以調用FlushViewOfFile函數來越過這個方式,強迫系統馬上將數據寫入到磁盤中去。


-----------------------------------------------------------------------------------

-----------------------------------------------------------------------------------

寫一個創建共享內存,並寫入數據

  1. #ifdef CHAR_TEST
  2. char* pData = NULL;
  3. #else
  4. HWND* pData = NULL;
  5. #endif // CHAR_TEST
  6. HANDLE hFileMap = NULL;
  7. hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, _T("WndData"));
  8. if (!hFileMap) // 不存在則創建
  9. {
  10. hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, _T("WndData"));
  11. }
  12. if (hFileMap != NULL)
  13. {
  14. #ifdef CHAR_TEST
  15. pData = (char*)MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0);
  16. #else
  17. pData = (HWND*)MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0);
  18. #endif // CHAR_TEST
  19. if (pData == NULL)
  20. {
  21. CloseHandle(hFileMap);
  22. hFileMap = NULL;
  23. }
  24. }
  25. HANDLE hMutex = CreateMutex(NULL, TRUE, _T("WndMutex"));
  26. #ifdef CHAR_TEST
  27. char* strValue = "123abcpStr";
  28. //pData = strValue;
  29. memcpy(pData, strValue, strlen(strValue));
  30. #else
  31. CStatic* pStcPic = (CStatic*)GetDlgItem(IDC_STC_PIC);
  32. HWND hWnd = pStcPic->m_hWnd;
  33. //pData = &hWnd;
  34. memcpy(pData, &hWnd, sizeof(HWND*));
  35. #endif // char_te
  36. //FlushViewOfFile(pData, sizeof(HWND*));
  37. ReleaseMutex(hMutex);

技術分享圖片

-----------------------------------------------------------------------------------

讀取共享數據:

  1. HANDLE hMutex = NULL;
  2. while (true)
  3. {
  4. hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, _T("WndMutex"));
  5. if (NULL != hMutex)
  6. {
  7. break;
  8. }
  9. Sleep(200);
  10. }
  11. WaitForSingleObject(hMutex, INFINITE);
  12. HANDLE hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, _T("WndData"));
  13. ASSERT(hFileMap);
  14. #if 1
  15. HWND* pData = (HWND*)MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  16. HWND hGet = *pData;
  17. #else
  18. char* pData = (char*)MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 1024);
  19. char* strTemp = pData;
  20. AfxMessageBox(strTemp);
  21. #endif
  22. HDC dc = ::GetDC(hGet);
  23. UnmapViewOfFile(pData);
  24. ReleaseMutex(hMutex);
技術分享圖片
在向共享內存寫值的時候,char* strValue = "123abcpStr";

再賦給 pData = strValue; 在讀取的時候會讀不到數據!

一定要用內存烤貝:memcpy(pData, strValue, strlen(strValue));

jpg 改 rar 技術分享圖片

Windows進程間共享內存通信實例