激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - C/C++ - win32下進(jìn)程間通信(共享內(nèi)存)實(shí)例分析

win32下進(jìn)程間通信(共享內(nèi)存)實(shí)例分析

2021-01-23 13:02C語(yǔ)言程序設(shè)計(jì) C/C++

這篇文章主要介紹了win32下進(jìn)程間通信(共享內(nèi)存)實(shí)例分析,對(duì)win32應(yīng)用程序及進(jìn)程的原理做了較為深入的剖析,需要的朋友可以參考下

一、概述

很多情況下在Windows程序中,各個(gè)進(jìn)程之間往往需要交換數(shù)據(jù),進(jìn)行數(shù)據(jù)通訊。WIN32 API提供了許多函數(shù)使我們能夠方便高效的進(jìn)行進(jìn)程間的通訊,通過(guò)這些函數(shù)我們可以控制不同進(jìn)程間的數(shù)據(jù)交換。

進(jìn)程間通訊(即:同機(jī)通訊)和數(shù)據(jù)交換有多種方式:消息、共享內(nèi)存、匿名(命名)管道、郵槽、Windows套接字等多種技術(shù)。“共享內(nèi)存”(shared memory)可以定義為對(duì)一個(gè)以上的進(jìn)程是可見(jiàn)的內(nèi)存或存在于多個(gè)進(jìn)程的虛擬地址空間。例如:如果兩個(gè)進(jìn)程使用相同的DLL,只把DLL的代碼頁(yè)裝入內(nèi)存一次,其他所有映射這個(gè)DLL的進(jìn)程只要共享這些代碼頁(yè)就可以了;利用消息機(jī)制實(shí)現(xiàn)IPC雖然有交換的數(shù)據(jù)量小、攜帶的信息少等缺點(diǎn),但由于其實(shí)現(xiàn)方便、應(yīng)用靈活而廣泛應(yīng)用于無(wú)須大量、頻繁數(shù)據(jù)交換的內(nèi)部進(jìn)程通訊系統(tǒng)之中。

二、同機(jī)進(jìn)程間共享內(nèi)存的實(shí)現(xiàn)

采用內(nèi)存映射文件實(shí)現(xiàn)WIN32進(jìn)程間的通訊:Windows中的內(nèi)存映射文件的機(jī)制為我們高效地操作文件提供了一種途徑,它允許我們?cè)赪IN32進(jìn)程中保留一段內(nèi)存區(qū)域,把硬盤(pán)或頁(yè)文件上的目標(biāo)文件映射到這段虛擬內(nèi)存中。注意:在程序?qū)崿F(xiàn)中必須考慮各進(jìn)程之間的同步問(wèn)題。

具體實(shí)現(xiàn)步驟如下:

1、在服務(wù)器端進(jìn)程中調(diào)用內(nèi)存映射API函數(shù)CreateFileMapping創(chuàng)建一個(gè)有名字標(biāo)識(shí)的共享內(nèi)存;

函數(shù)CreateFileMapping原型如下:

?
1
2
3
4
5
6
7
8
HANDLE CreateFileMapping (
HANDLE hFile, // 映射文件的句柄,若設(shè)為0xFFFFFFFF(即:INVALID_HANDLE_VALUE)則創(chuàng)建一個(gè)進(jìn)程間共享的對(duì)象
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, //安全屬性
DWORD flProtect, //保護(hù)方式
DWORD dwMaximumSizeHigh, //對(duì)象的大小
DWORD dwMaximumSizeLow,
LPCTSTR lpName // 映射文件名,即共享內(nèi)存的名稱
);

與虛擬內(nèi)存類似,保護(hù)方式參數(shù)可以是PAGE_READONLY或是PAGE_READWRITE。如果多進(jìn)程都對(duì)同一共享內(nèi)存進(jìn)行寫(xiě)訪問(wèn),則必須保持相互間同步。映射文件還可以指定PAGE_WRITECOPY標(biāo)志,可以保證其原始數(shù)據(jù)不會(huì)遭到破壞,同時(shí)允許其他進(jìn)程在必要時(shí)自由的操作數(shù)據(jù)的拷貝。

例如:創(chuàng)建一個(gè)名為“zzj”的長(zhǎng)度為4096字節(jié)的有名映射文件:

?
1
HANDLE m_hMapFile=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,0x1000," zzj");

2、在創(chuàng)建文件映射對(duì)象后,服務(wù)器端進(jìn)程調(diào)用MapViewOfFile函數(shù)映射到本進(jìn)程的地址空間內(nèi);
例:映射緩存區(qū)視圖

?
1
void* m_pBaseMapFile=MapViewOfFile(m_hMapFile,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);

3、客戶端進(jìn)程訪問(wèn)共享內(nèi)存對(duì)象,需要通過(guò)內(nèi)存對(duì)象名調(diào)用OpenFileMapping函數(shù),以獲得共享內(nèi)存對(duì)象的句柄

?
1
HANDLE m_hMapFile =OpenFileMapping(FILE_MAP_WRITE,FALSE," zzj");

4、如果客戶端進(jìn)程獲得共享內(nèi)存對(duì)象的句柄成功,則調(diào)用MapViewOfFile函數(shù)來(lái)映射對(duì)象視圖。用戶可以使用該對(duì)象視圖來(lái)進(jìn)行數(shù)據(jù)讀寫(xiě)操作,以達(dá)到數(shù)據(jù)通訊的目的。
例:映射緩存區(qū)視圖

?
1
void* m_pBaseMapFile=MapViewOfFile(m_hMapFile,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);

5、當(dāng)用戶進(jìn)程結(jié)束使用共享內(nèi)存后,調(diào)用UnmapViewOfFile函數(shù)以取消其地址空間內(nèi)的視圖:

?
1
2
3
4
5
if (m_pBaseMapFile)
{
  UnmapViewOfFile(m_pBaseMapFile);
  SharedMapView=NULL;
}

三、使用文件映射實(shí)現(xiàn)共享內(nèi)存。

FileMapping用于將存在于磁盤(pán)的文件放進(jìn)一個(gè)進(jìn)程的虛擬地址空間,并在該進(jìn)程的虛擬地址空間中產(chǎn)生一個(gè)區(qū)域用于“存放”該文件,這個(gè)空間就叫做File View(存放在進(jìn)程的虛擬內(nèi)存中),系統(tǒng)并同時(shí)產(chǎn)生一個(gè)File Mapping Object(存放于物理內(nèi)存中)用于維持這種映射關(guān)系,這樣當(dāng)多個(gè)進(jìn)程需要讀寫(xiě)那個(gè)文件的數(shù)據(jù)時(shí),它們的File View其實(shí)對(duì)應(yīng)的都是同一個(gè)File Mapping Object,這樣做可節(jié)省內(nèi)存和保持?jǐn)?shù)據(jù)的同步性,并達(dá)到數(shù)據(jù)共享的目的。

當(dāng)然在一個(gè)應(yīng)用向文件中寫(xiě)入數(shù)據(jù)時(shí),其它進(jìn)程不應(yīng)該去讀取這個(gè)正在寫(xiě)入的數(shù)據(jù)。這就需要進(jìn)行一些同步的操作。下邊來(lái)看一下具體的API。

CreateFileMaping的用法:

?
1
2
3
4
5
6
7
8
9
10
HANDLE CreateFileMapping( //返回FileMapping Object的句柄
HANDLE hFile, //想要產(chǎn)生映射的文件的句柄
LPSECURITY_ATTRIBUTES lpAttributes, //安全屬性(只對(duì)NT和2000生效)
DWORD flProtect, //保護(hù)標(biāo)致
DWORD dwMaximumSizeHigh, //在DWORD的高位中存放
File Mapping Object //的大小
DWORD dwMaximumSizeLow, //在DWORD的低位中存放
File Mapping Object //的大小(通常這兩個(gè)參數(shù)有一個(gè)為0)
LPCTSTR lpName //File Mapping Object的名稱。
);

1)物理文件句柄

任何可以獲得的物理文件句柄,如果你需要?jiǎng)?chuàng)建一個(gè)物理文件無(wú)關(guān)的內(nèi)存映射也無(wú)妨,將它設(shè)置成為 0xFFFFFFFF(INVALID_HANDLE_VALUE)就可以了.

如果需要和物理文件關(guān)聯(lián),要確保你的物理文件創(chuàng)建的時(shí)候的訪問(wèn)模式和"保護(hù)設(shè)置"匹配,比如:物理文件只讀,內(nèi)存映射需要讀寫(xiě)就會(huì)發(fā)生錯(cuò)誤。推薦你的物理文件使用獨(dú)占方式創(chuàng)建。

如果使用 INVALID_HANDLE_VALUE,也需要設(shè)置需要申請(qǐng)的內(nèi)存空間的大小,無(wú)論物理文件句柄參數(shù)是否有效,這樣 CreateFileMapping就可以創(chuàng)建一個(gè)和物理文件大小無(wú)關(guān)的內(nèi)存空間給你,甚至超過(guò)實(shí)際文件大小,如果你的物理文件有效,而大小參數(shù)為0,則返回給你的是一個(gè)和物理文件大小一樣的內(nèi)存空間地址范圍。返回給你的文件映射地址空間是可以通過(guò)復(fù)制,集成或者命名得到,初始內(nèi)容為0。

2)保護(hù)設(shè)置

就是安全設(shè)置,不過(guò)一般設(shè)置NULL就可以了,使用默認(rèn)的安全配置. 在win2k下如果需要進(jìn)行限制,這是針對(duì)那些將內(nèi)存文件映射共享給整個(gè)網(wǎng)絡(luò)上面的應(yīng)用進(jìn)程使用是,可以考慮進(jìn)行限制.

3)高位文件大小

32位地址空間,設(shè)置為0。

4) 共享內(nèi)存名稱

命名可以包含 "Global"或者 "Local" 前綴在全局或者會(huì)話名空間初級(jí)文件映射.其他部分可以包含任何除了()以外的字符,可以參考 Kernel Object Name Spaces.

5)調(diào)用CreateFileMapping的時(shí)候GetLastError的對(duì)應(yīng)錯(cuò)誤

ERROR_FILE_INVALID 如果企圖創(chuàng)建一個(gè)零長(zhǎng)度的文件映射,應(yīng)有此報(bào)
ERROR_INVALID_HANDLE 如果發(fā)現(xiàn)你的命名內(nèi)存空間和現(xiàn)有的內(nèi)存映射,互斥量,信號(hào)量,臨界區(qū)同名就麻煩了
ERROR_ALREADY_EXISTS 表示內(nèi)存空間命名已經(jīng)存在

使用函數(shù)CreateFileMapping創(chuàng)建一個(gè)想共享的文件數(shù)據(jù)句柄,然后使用MapViewOfFile來(lái)獲取共享的內(nèi)存地址,然后使用OpenFileMapping函數(shù)在另一個(gè)進(jìn)程里打開(kāi)共享文件的名稱,這樣就可以實(shí)現(xiàn)不同的進(jìn)程共享數(shù)據(jù)。

代碼示例:這個(gè)程序包括一個(gè)客戶端和一個(gè)服務(wù)端,服務(wù)端創(chuàng)建共享內(nèi)存,客戶端打開(kāi)共享內(nèi)存,兩者通過(guò)兩個(gè)事件互斥訪問(wèn)共享內(nèi)存,實(shí)現(xiàn)一個(gè)小功能,就是服務(wù)端進(jìn)程從控制臺(tái)讀入數(shù)據(jù)發(fā)送給客戶端進(jìn)程。

服務(wù)端:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#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;
  }
 
  hMutex = CreateMutex(NULL, FALSE, L"SM_Mutex");
  if (NULL == hMutex || ERROR_ALREADY_EXISTS == GetLastError())
  {
    cout << "CreateMutex" << GetLastError() << endl;
    goto SERVER_SHARE_MEMORY_END;
  }//多個(gè)線程互斥訪問(wèn)
 
  //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;//把指定的事件對(duì)象設(shè)置為無(wú)信號(hào)狀態(tài)
    if (!SetEvent(hServerWriteOver)) goto SERVER_SHARE_MEMORY_END;//把指定的事件對(duì)象設(shè)置為有信號(hào)狀態(tài)
  } 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;
}

客戶端:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#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 一旦互斥對(duì)象處于有信號(hào)狀態(tài),則該函數(shù)返回
  {
    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;
}

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产日韩在线观看一区 | 免费看一级毛片欧美 | xxnxx中国18| 国产亚洲精品久久久久5区 99精品视频在线 | 成人青青草| 中文字幕免费在线观看视频 | 91网站免费观看 | 国产一区精品在线观看 | 91麻豆精品国产91久久久点播时间 | 激情小说区 | 欧美三级美国一级 | 综合在线一区 | 久久夜夜视频 | 一区二区精品在线 | hdjapanesemassagehd日本 | 亚洲国产精品久久久久婷婷老年 | 在线观看免费毛片视频 | 老师你怎么会在这第2季出现 | 日韩精品网站在线观看 | 欧美日韩在线视频观看 | 日韩在线视频导航 | xxxx69hd一hd| 日日草天天干 | 91系列在线观看 | 日本最新免费二区三区 | 男女做性免费网站 | 欧美一级黄色片免费观看 | 久久精品亚洲精品国产欧美kt∨ | 一区二区三区黄色 | 成人性生活视频在线播放 | 成年性羞羞视频免费观看无限 | 欧美在线综合视频 | 国产九色视频在线观看 | 午夜精品老牛av一区二区三区 | 天天夜夜草 | 福利免费视频 | 国产精品久久久免费 | 欧美一级做性受免费大片免费 | 午夜精品久久久久久久爽 | 中国成人在线视频 | 内地av在线 |