Linux-内存共享映射

进程间通信-内存共享映射

一、简述

  • mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。
  • mmap()的作用是映射文件描述符fd指定文件的 [off,off + len]区域至调用进程的[addr, addr + len]的内存区域, 如下图所示:

二、mmap 函数

功能
mmap() 可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存
地址,对文件的读写可以直接用指针来做而不需要read/write函数。

头文件

#include <sys/mman.h>

函数原型

void* mmap ( void * addr , size_t len , int prot , 
					int flags , int fd , off_t offset ) 

参数说明

  • addr:指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。
  • len:是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。
  • prot:指定空想内存的访问权限。可取如下几个值的或:PROT_READ(可读)、PROT_WRITE(可写)、PROT_EXEC(可执行)、PROT_NONE(不可访问)。
  • flag:由以下几个常值指定:MAP_SHARED、MAP_PRIVATE、MAP_FIXED,其中,MAP_SHARED,MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。
    • MAP_SHARED:多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修
      改,另一个进程也会看到这种变化。
    • MAP_PRIVATE:多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修
      改,另一个进程并不会看到这种变化,也不会真的写到文件中去。
  • fd:为即将映射到进程空间的文件描述字,一般由open()返回,同时,fd可以指定为-1,此时须指定flags参数中的MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的进程间进行通信)。
  • offset:表示偏移量,一般设为0,表示从文件头开始映射。

返回值
函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。

三、应用示例

mmap_w.c

/* process_mmap_w.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#define MAPLEN 0x1000 //十进制4096

//用于进程间通信,一般设置为结构体,用来传输数据 
struct STU {
	int id;
	char name[20];
	char sex;
};

//自定义的出错的处理函数 
void sys_err(char *str, int exitno) {
	perror(str);
	exit(exitno);
}

//从终端传入文件名 
int main(int argc, char *argv[]) {
	struct STU *mm;
	int fd, i = 0;
	
	// 没有从终端传入文件名产生错误 
	if (argc < 2) {
		printf("./a.out filename\n");
		exit(1);
	}
	
	//根据传入的 argv[1]文件名打开相应的临时文件 
	fd = open(argv[1], O_RDWR | O_CREAT, 0777);
	
	//磁盘文件大小不为零 
	if (fd < 0)
		sys_err("open", 1);
	
	//在文件MAPLEN位置写入数据,从而扩从fd文件大小为MAPLEN 
	if (lseek(fd, MAPLEN-1, SEEK_SET) < 0)
		sys_err("lseek", 3); 
	if (write(fd, "\0", 1) < 0)
		sys_err("write", 4);
		
		
	//共享内存映射 	
	//参数1 :null:由操作系统找内存的空位 
	//参数2:MAPLEN内存长度
	//参数3:port页面属性 读写
	//参数4: MAP_SHARED 内存更改 文件也更改
	//参数5:fd 你要映射的磁盘文件 
	//参数6:0 偏移量从 0 开始 
	mm = mmap(NULL, MAPLEN, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	
	
	//映射发生错误 
	if (mm == MAP_FAILED)
		sys_err("mmap", 2);
	
	//关闭文件描述符	
	close(fd);
	
	while (1) {
		
		//往内存中写入数据 
		mm->id = i;
		sprintf(mm->name, "zhang-%d", i);
		if (i % 2 == 0)
			mm->sex = 'm';
		else
			mm->sex = 'w';
		i++;
		sleep(1);
	}
	
	//解除映射关系 
	munmap(mm, MAPLEN);
	
	return 0;
}

mmap_r.c

/* process_mmap_r.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#define MAPLEN 0x1000
struct STU {
	int id;
	char name[20];
	char sex;
};
void sys_err(char *str, int exitno) {
	perror(str);
	exit(exitno);
}
int main(int argc, char *argv[]) {
	struct STU *mm;
	int fd, i = 0;
	if (argc < 2) {
		printf("./a.out filename\n");
		exit(1);
	}
	fd = open(argv[1], O_RDWR);
	if (fd < 0)
		sys_err("open", 1);
	mm = mmap(NULL, MAPLEN, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if (mm == MAP_FAILED)
		sys_err("mmap", 2);
	close(fd);
	
	//释放我们创建的本地文件(映射的文件设置为临时文件)
	unlink(argv[1]);
	
	while (1) {
		printf("%d\n", mm->id);
		printf("%s\n", mm->name);
		printf("%c\n", mm->sex);
		sleep(1);
	}
	munmap(mm, MAPLEN);
	return 0;
}

运行结果:

进程1:写
在这里插入图片描述

进程2:读

参考来源:
https://blog.csdn.net/windgs_yf/article/details/81146887

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值