一、共享内存原理
在32位的系统中,每一个进程都有4G“连续”的虚拟内存,且每一个进程这4G的虚拟内存块是互不共享。而为达到每个进程能够操作同一块内存,Window提供了内存映射文件的方式,简单的说每一个进程的一段虚拟内存对应于同一个文件或类文件的资源,使得每个进程能够操作同一个文件或类文件资源,从而达到内存共享的效果。
(1)为什么是4G?
32位系统寻址 2^32 = 4G
(2)连续的虚拟内存
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
(3)文件映射
内存映射文件(Memory-mapped file),或称“文件映射”、“映射文件”,是一段虚内存逐字节对应于一个文件或类文件的资源,使得应用程序处理映射部分如同访问主内存。
特别提醒:因为共享内存并没有提供同步机制,所以每个线程在访问临界区资源(共享内存)时,会相互影响,比如,一个进程正在写入,另一个进程同时也在写入,导致写入的数据错乱。所以为了解决这个,可以用到同步对象--Event。
二、一个小Demo
(1)Server流程:
1.创建共享文件
2.文件映射
3.获取映射首地址
4.读写数据
5.关闭文件句柄,卸载文件映射,关闭文件映射句柄
// ProcessA.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <Windows.h>
#include <iostream>
using namespace std;
#define BUFFER_SIZE 256
#define FILE_MAPPING_NAME L"FILE_MAPPING_NAME"
#define EVENT_NAME1 L"EVNET_NAME1"
#define EVENT_NAME2 L"EVNET_NAME2"
int main()
{
HANDLE hFile = NULL;
HANDLE hMap = NULL;
char szBufIn[BUFFER_SIZE] = { 0 };
char szBufOut[BUFFER_SIZE] = { 0 };
LPTSTR pBeginAddress = NULL;
//创建共享的文件
hFile = CreateFile(
L"一个路径",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if (NULL == hFile)
{
cout << "CreateFile failed!" << endl;
return 0;
}
//创建文件映射
hMap = CreateFileMapping(
hFile,
NULL,
PAGE_READWRITE,
0,
BUFFER_SIZE,
FILE_MAPPING_NAME
);
if (!hMap)
{
cout << "CreateFileMapping Failed!" << endl;
return 0;
}
//获取映射首地址
pBeginAddress = (LPTSTR)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, BUFFER_SIZE);
if (!pBeginAddress)
{
cout << "MapViewOfFile failed!" << endl;
return 0;
}
HANDLE hEvent1 = CreateEvent(NULL, TRUE, TRUE, EVENT_NAME1);
HANDLE hEvent2 = CreateEvent(NULL, TRUE, FALSE, EVENT_NAME2);
while (true)
{
ZeroMemory(szBufIn, BUFFER_SIZE);
ZeroMemory(szBufOut, BUFFER_SIZE);
WaitForSingleObject(hEvent1, INFINITE);
memcpy(szBufOut, pBeginAddress, BUFFER_SIZE);
cout << "Shared Memory:" << szBufOut << endl;
cout << "Pls:";
cin.getline(szBufIn, BUFFER_SIZE);
memcpy(pBeginAddress, szBufIn, BUFFER_SIZE);
ResetEvent(hEvent1);
SetEvent(hEvent2);
}
CloseHandle(hEvent1);
CloseHandle(hEvent2);
CloseHandle(hFile);
UnmapViewOfFile(hMap);
CloseHandle(hMap);
}
(2)Client流程
1.打开文件映射
2.获取映射首地址
3.读写数据
4.关闭文件句柄,卸载文件映射,关闭文件映射句柄
// ProcessB.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <Windows.h>
#include <iostream>
using namespace std;
#define BUFFER_SIZE 256
#define FILE_MAPPING_NAME L"FILE_MAPPING_NAME"
#define EVENT_NAME1 L"EVNET_NAME1"
#define EVENT_NAME2 L"EVNET_NAME2"
int main()
{
HANDLE hFile = NULL;
HANDLE hMap = NULL;
char szBufIn[BUFFER_SIZE] = { 0 };
char szBufOut[BUFFER_SIZE] = { 0 };
LPTSTR pBeginAddress = NULL;
//打开文件映射
hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,FILE_MAPPING_NAME);
if (!hMap)
{
cout << "OpenFileMapping Failed!" << endl;
return 0;
}
//获取映射首地址
pBeginAddress = (LPTSTR)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, BUFFER_SIZE);
if (!pBeginAddress)
{
cout << "MapViewOfFile failed!" << endl;
return 0;
}
HANDLE hEvent1 = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME1);
HANDLE hEvent2 = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME2);
while (true)
{
ZeroMemory(szBufIn, BUFFER_SIZE);
ZeroMemory(szBufOut, BUFFER_SIZE);
WaitForSingleObject(hEvent2, INFINITE);
memcpy(szBufOut, pBeginAddress, BUFFER_SIZE);
cout << "Shared Memory:" << szBufOut << endl;
cout << "Pls:";
cin.getline(szBufIn, BUFFER_SIZE);
memcpy(pBeginAddress, szBufIn, BUFFER_SIZE);
ResetEvent(hEvent2);
SetEvent(hEvent1);
}
CloseHandle(hEvent1);
CloseHandle(hEvent2);
CloseHandle(hFile);
UnmapViewOfFile(hMap);
CloseHandle(hMap);
}