Linux系统编程------mmap函数

mmap

void *mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset)    // 创建共享内存映射

参数:
addr: 指定映射区的首地址。通常传NULL,表示让系统自动分配;
length:共享内存映射区的大小;(<= 文件的实际大小)
prot:共享内存映射区的读写属性; PROT_READ、PROT_WRITE、PROT_READ | PROT_WRITE
flags:标注共享内存的共享属性;MAP_SHARED、MAP_PRIVATE
fd:用于创建共享内存映射区的那个文件的 文件描述符;
offset:偏移位置,默认0,表示文件全部。必须是4K的整数倍

返回值:
成功:映射区的首地址;
失败:MAP_FAILED((void*)-1),errno

munmap

int munmap(void* addr, size_t length);       // 释放映射区

参数:
addr:mmap 的返回值;
length:大小
返回值:
成功:0;
失败:-1。

代码

#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/mman.h>

int main(int argc, char* argv[])
{

	int fd;
	char* p=NULL;

	fd=open("testmap", O_RDWR|O_CREAT|O_TRUNC, 0664);
	if(fd==-1){
		perror("open error");
	}

	/*
	lseek(fd, 10, SEEK_END);    // 扩展文件大小
	write(fd, "\0", 1);
	*/
	ftruncate(fd, 20);   // 需要写权限才能扩展文件大小
	int len=lseek(fd, 0, SEEK_END);

	p=mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if(p == MAP_FAILED){
		perror("mmap error");
	}

	// 使用p对文件进行读写操作
	strcpy(p, "hello mmap");

	printf("------------%s\n",p);
	
	int ret=munmap(p, len);    // 释放映射区
	if(ret==-1){
		perror("munmap error");
	}
	close(fd);
	return 0;
}

使用注意
1、用于创建映射区的文件大小为0,实际指定非0大小,创建映射区,出现总线错误;
2、用于创建映射区的文件大小为0,实际指定0大小,创建映射区,出现无效参数错误;
3、创建映射区,需要read权限,当访问权限为MAP_SHARED时,mmap的读写权限,应该 <= 文件的open权限, 只写是不行的。
4、文件描述符fd,在mmap创建映射区完成即可关闭。后续访问文件,用 地址访问。
5、 offset必须是4096的整数倍.(MMU映射的最小单位是 4K)。
6、对申请的内存不能越界访问。
7、映射区访问权限为MAP_PRIVATE,对内存所做的所有修改,只在内存有效,不会反映到物理磁盘上。
8、映射区访问权限为MAP_PRIVATE,只需要open文件时,有读权限,用于创建映射区即可。

保险调用方式

1、fd = open(“文件名”, O_RDWR);
2、mmap(NULL, 有效文件大小, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

mmap父子进程间通信

1、父进程 先 创建映射区,open(O_RDWR), mmap(MAP_SHARED);
2、指定 MAP_SHARED权限;
3、fork()创建子进程;
4、一个进程读,一个进程写。

include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h>

int var = 100;

int main(void)
{
	int *p;
	int pid;

	int fd;
	fd=open("temp", O_RDWR|O_CREAT|O_TRUNC, 0644);
	if(fd<0){
		perror("open error");
		exit(1);
	}
	ftruncate(fd, 4);

	p=(int*)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);  // 创建映射区
	if(p == MAP_FAILED){
		perror("mmap error");
		exit(1);
	}
	close(fd);

	pid = fork();
	if(pid == 0){
		*p=2000;
		var=1000;
		printf("child, *p = %d, var = %d\n",*p, var);
	}else if(pid > 0){
		sleep(1);
		printf("parent, *p = %d, var = %d\n",*p, var);
		wait(NULL);

		int ret = munmap(p, 4);    // 释放映射区
		if(ret == -1){
			perror("munmap error");
			exit(1);
		}
	}
	
	return 0;
}

非血缘关系进程间通信

1、两个进程 打开同一个文件,创建映射区;
2、指定flags为MAP_SHARED;
3、一个写入、一个读出。

【注意】:无血缘关系进程通信,
mmap:数据可以重复读取;
fifo:数据只能读取一次。

写进程

include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/mman.h>
#include<fcntl.h>

struct student{
	int id;
	char name[256];
	int age;
};

int main(int argc, char* argv[])
{
	struct student stu = {10, "xiaoming", 18};
	struct student *p;
	int fd;
	fd = open("test_map", O_RDWR|O_CREAT|O_TRUNC, 0664);
	if(fd == -1){
		perror("open error");
		exit(1);
	}

	ftruncate(fd, sizeof(stu));
	
	p = mmap(NULL, sizeof(stu), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if(p == MAP_FAILED){
		perror("mmap error");
		exit(1);
	}

	while(1){
		memcpy(p, &stu, sizeof(stu));
		stu.id++;
		sleep(1);
	}

	munmap(p, sizeof(stu));

	return 0;
	
}

读进程

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<sys/mman.h>

struct student{
	int id;
	char name[256];
	int age;
};

int main(int argc, char* argv[])
{

	struct student stu;
	struct student *p;
	int fd;

	fd = open("test_map", O_RDONLY);
	if(fd == -1){
		perror("open error");
		exit(1);
	}

	p = mmap(NULL, sizeof(stu), PROT_READ, MAP_SHARED, fd, 0);
	if(p == MAP_FAILED){
		perror("mmap error");
		exit(1);
	}

	close(fd);

	while(1){
		printf("id = %d, name = %s, age = %d\n", p->id, p->name, p->age);
		sleep(1);
	}

	munmap(p, sizeof(stu));

	return 0;
}

匿名映射
只能用于血缘关系间的进程通信。

p = (int*) mmap(NULL, 所需大小长度, PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS, -1, 0);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值