实验四:进程间共享内存
1.实验目的:
通过实验了解windows如何通过内存映射文件机制来实现进程间共享内存;
2.实验内容
(1)创建一个写进程,创建一个命名的内存映射文件,将一个文件映射对象映射到当前应用程序的虚拟地址空间,在虚拟地址空间中写入数据;
(2)创建一个读进程,打开命名的内存映射文件,将文件映射对象映射到当前应用程序的虚拟地址空间,在虚拟地址空间中读出数据。
3.实验步骤:
程序一:写进程
实验描述:
(1) 利用CreateFileMapping()创建一个命名的内存映射文件对象;
(2) 利用MapViewOfFile()将文件映射到当前应用程序的虚拟地址空间;
(3)在虚拟地址空间中写入数据。
代码实现:
// 进程间共享内存写.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <iostream>
/*
在A进程,我们通过 CreateFileMapping()函数来创建一个文件映射对象(使用 INVAILD_HANDLE_VALUE 来不指定文件句柄),
然后调用MapFileOfView()函数来将文件映射对象映射到本进程中,
利用copymemory来进行内存读写。
在B进程,我们通过 OpenFileMapping()来打开,
然后调用MapFileOfView()函数来将文件映射对象映射到本进程中,
利用copymemory来进行内存读写。
*/
int main(int argc, char* argv[])
{
HANDLE lhShareMemory;
char* lpBuffer = NULL;
//创建一个和物理文件无关的内存映射文件对象(换出时使用页文件)。
/*
HANDLE CreateFileMapping(HANDLE hFile,
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
LPCTSTR lpName);
hFile:指定欲在其中创建映射的一个文件句柄。
0xFFFFFFFF(-1,即INVALID_HANDLE_VALUE)表示换出时使用页文件。
dwMaximumSizeHigh:文件映射的最大长度的高32位,
dwMaximumSizeLow:文件映射的最大长度的低32位,
如果这两个参数都是零,就用磁盘文件的实际长度。
*/
//CreateFileMapping()函数来创建一个文件映射对象(使用 INVAILD_HANDLE_VALUE 来不指定文件句柄)
lhShareMemory = CreateFileMapping(HANDLE(0xFFFFFFFF), NULL, PAGE_READWRITE,
0, 100, "mySharedMemory");
if (NULL == lhShareMemory)
{
if (ERROR_ALREADY_EXISTS == GetLastError())
{
std:: cout << "Already exists!"<<std:: endl;
}
else
{
std::cout << "Create Sheared Memory unsuccessfully!"<< std::endl;
}
return 0;
}
//把文件或文件的一部分映射到进程的虚拟地址空间。
/*
LPVOID MapViewOfFile(HANDLE hFileMappingObject,
DWORD dwDesiredAccess,
DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow,
DWORD dwNumberOfBytesToMap);
*/
//MapFileOfView()函数来将文件映射对象映射到本进程中
lpBuffer = (char*)MapViewOfFile(lhShareMemory, FILE_MAP_WRITE, 0, 0, 100);
if (NULL == lpBuffer)
{
std::cout << "Get Share memory unsuccessfully!"<< std::endl;
return 0;
}
//写入数据
strcpy(lpBuffer, "Hello,every students,please study hard! ");
std::cout << "进程通信:采用共享内存" << std::endl;
std::cout << "写进程" << std::endl;
std::cout << "写入数据:"<< std::endl<<lpBuffer << std::endl;
getchar();
//取消映射文件视图
UnmapViewOfFile(lpBuffer);
return 0;
}
程序二:读进程
实验描述:
(1) 利用OpenFileMapping()打开已创建的命名内存映射文件对象;
(2) 利用MapViewOfFile()将文件映射到当前应用程序的虚拟地址空间;
(3)从虚拟地址空间中读出数据。
代码描述:
// 进程间共享内存读.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include ".\..\实验三第三题\实验三虚拟内存的检测.cpp"
using namespace std;
int main(int argc, char* argv[])
{
HANDLE lhShareMemory;
char* lpcBuffer;
lhShareMemory = OpenFileMapping(FILE_MAP_READ, false, "mySharedMemory");
// void WalkVM(HANDLE hProcess,char* pBlock)
if (NULL == lhShareMemory)
{
std::cout << "Open share memory unsuccessfully!" << std::endl;
DWORD ldwError = GetLastError();
std::cout << ldwError;
return 0;
}
//把文件或文件的一部分映射到进程的虚拟地址空间。
/*
LPVOID MapViewOfFile(HANDLE hFileMappingObject,
DWORD dwDesiredAccess,
DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow,
DWORD dwNumberOfBytesToMap);
*/
lpcBuffer = (char*)MapViewOfFile(lhShareMemory, FILE_MAP_READ, 0, 0, 100);
if (NULL == lpcBuffer)
{
std::cout << "Open share memory unsuccessfully!";
return 0;
}
//std::cout << "::GetCurrentProcess()===>" <<hex<< lpcBuffer << std::endl;
printf("%x'\n'", lpcBuffer);
std::cout << "进程通信:采用共享内存" << std::endl;
std::cout << "读进程" << std::endl;
std::cout << "读入数据:" << std::endl;
for (int i = 0; i < 100; ++i)
{
std::cout << *(lpcBuffer + i);
}
cout<<endl;
::WalkVM(::GetCurrentProcess());
getchar();
UnmapViewOfFile(lpcBuffer);
return 0;
}
/*
思考题:
1.Windows下的进程间共享内存是利用什么机制实现的?
内有的映射文件 映射
基于共享存储区的共享存储器系统机制
内存映射文件,把对文件的操作转变成对内存的操作
2.对于读写进程,物理内存是什么时候分配的?
读写进程物理内存是写时分配的, 读时不重重新分配。
首次使用的时候,对于写如数据时 strcpy(lpBuffer, "Hello,every students,please study hard! ");时候分配了物理内存,对于读进程不会分配。
3.读写进程之间的同步和互斥在共享内存机制中已经存在了,还是需要用户自己来实现?
需要用户自己来实现
共享内存并未提供进程同步和互斥机制,使用共享内存完成进程间通信时,需要借助互斥量或者信号量来完成进程的同步。
4.利用“虚拟内存的检测”程序检测读进程所映射的虚拟地址空间块的信息。
//引入虚拟内存检测的文件
#include ".\..\实验三第三题\实验三虚拟内存的检测.cpp"
//当前所使用的的虚拟内存块(以16进制形式输出)
printf("%x'\n'", lpcBuffer);
//调用虚拟内存检测函数
::WalkVM(::GetCurrentProcess());
001d0000-001d1000 (4.00 KB) Committed, READONLY, Mapped
*/