2021-06-10

windows平台内存映射文件的使用记录

背景

内存映射文件广泛应用于IPC(进程间通信),其原理是通过在内核空间中创建一个与磁盘文件的映射关系,各个进程读写该内存映射文件的操作与操作进程内的字符数组完全一致。

步骤

  1. 创建普通文件句柄。
    主要包含指定访问方式(可读、可写等)

  2. 根据文件句柄创建用于内存映射的内核对象句柄。
    需要指明内核对象的容量大小和访问方式。
    如果用于进程间通信,需要创建命名的内核对象,此名称的命名空间是属于操作系统层面的全局。

  3. 将内存映射文件映射到当前进程的地址空间
    需要指定映射的偏移地址和映射的长度,此处容易出现由于偏移地址不符合特定偏移单元的倍数导致映射失败(GetLastError 1132)

  4. 至此,内存映射文件已经完整的构造成功,按照字符数组的操作方式即可进行读写(是否可读、可写需依据创建句柄时给定的参数)。

  5. 进程间通信时,通常通过互斥量和信号量进行同步,通过内存映射文件进行数据通信。数据通信时一般创建命名的内存映射文件,这样在进程间创建内存映射文件时才能确保都连接至统一的内存文件中(总线)

  6. 退出时通过相反的顺序进行退出即可。
    6.1 卸载内存映射文件至当前进程的映射
    6.2 关闭映射文件句柄
    6.3 关闭普通文件句柄

  7. 代码示例
    如下代码通过标记区分当前是写端(读端),读端读取10次数据之后退出;写端写10此数据之后退出。

#include <Windows.h>
#include <iostream>
#include <memory>
#include <thread>
using namespace std;

int main(int argc, char** argv)
{
	HANDLE hfile = CreateFile("MemFile.XXX", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
		OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE != hfile)
	{
		printf("Create File Success!\n");
	}
	else
	{
		return -1;
	}
	// 
	HANDLE hcoreFileMap = CreateFileMapping(hfile, NULL, PAGE_READWRITE, 0, 128, "TEST_FILE_XXTL");
	if (hcoreFileMap == NULL)
	{
		CloseHandle(hfile);
		printf("CreateFileMapping Failed.%u\n", GetLastError());
		return -1;
	}

	LPVOID lpBuffer = MapViewOfFile(hcoreFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 32);		//	20 - 21 - 40
	if (lpBuffer == NULL)
	{
		printf("MapViewOfFile Failed.%u\n", GetLastError());

		CloseHandle(hcoreFileMap);
		CloseHandle(hfile);
		return -1;
	}
	char* pBuffer = (char*)lpBuffer;
	if (argc == 1)		// 读值
	{
		thread t([&]()->void {
			int i = 0;
			pBuffer[0] = 0;
			while (i < 10)
			{
				if (pBuffer[0] == 0)
				{
					// 没有数据
					std::this_thread::sleep_for(std::chrono::milliseconds(200));
					continue;
				}
				i++;
				{
					// 10 次
					int nLen = pBuffer[0];
					char* p = new char[nLen + 1];
					strncpy(p, pBuffer + 1, nLen);
					p[nLen] = 0;
					printf("time %d %s\n",i, p);
					delete[]p;

					pBuffer[0] = 0;		// 标记已经读取完成
				}

			
			}
			printf("Process Read finished.\n");
		});
		t.join();
	}
	else
	{
		// 写值
		thread t([&]()->void {
			int i = 0;
			pBuffer[0] = 0;
			while (i < 10)
			{
				char ch[256] = { 0 };
				scanf("%s", ch);

				int nLen = strlen(ch);
				if (nLen > 20)
				{
					ch[20] = 0;
					nLen = 20;
				}
				strncpy(pBuffer + 1, ch, nLen);
				pBuffer[0] = nLen;
				while(pBuffer[0] != 0)
				{
					// 等待接收端接收
					std::this_thread::sleep_for(std::chrono::milliseconds(200));
					printf("wait once\n");
				}
				i++;
			}

			printf("Process Write finished.\n");
		});
		t.join();
	}
	
	printf("to exit Process\n");
	UnmapViewOfFile(lpBuffer);
	CloseHandle(hcoreFileMap);
	CloseHandle(hfile);

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值