Linux——mmap函数、父子进程间mmap通信、无血缘关系间mmap通信、mmap匿名映射区

一、存储映射I/O(磁盘内容映射到内存)

一、概念理解
存储映射I/O(Memory-mapped I/O)使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区中取数据,就相当于读文件中的相应字节。与此类似,将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可以在不使用read和write函数的情况下,使用地址(指针)完成I/O操作。

(本来在磁盘上的内容,想要去读写就需要open打开再去read或者write,但是一旦映射到了内存上,就可以利用地址使用指针去操作,这样对文件的操作就有了更多的方法,当然也就可以修改内存直接改变磁盘文件)

使用这种方法,首先应通知内核,将一个指定文件映射到存储区域中,这个映射工作可以通过mmap函数来实现
在这里插入图片描述
二、mmap函数原型
在这里插入图片描述三、mmap建立映射区

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

void sys_err(const char *str)
{
	perror(str);
	exit(1);
}
//根据存储映射函数的参数依次地去进行操作
//mmap(映射区首地址NULL,映射区长度,读写属性,映射区属性是否同步shared/private,文件描述符,偏移即映射文件的区域)
int main(int argc, int char* argv[])
{
	//假设字符串映射
	char *p = NULL;
	int fd;
	fd = open("testmap", O_RDWR|O_CREATE|O_TRUNC,0644);
	if(fd == -1)
	{
		sys_err("open error");
	}
	//但是大小为0的文件是不能映射的,因此要扩展文件大小
	lseek(fd,10,SEEK_END);
	write(fd,"\0",1);//拓展文件成11
	int len = lseek(fd,0,SEEK_END)//用lseek获取文件大小
	//或者用truncate/ftruncate获取文件大小
	
	p = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	if(p == MAP_FILED)
	{
		sys_err("mmap error");
	}
	
	//使用p对文件进行读写操作
	strcpy(p,"hell0 mmap\n");//写操作
	printf("-------%s",p);
	
	int ret = munmap(p, lem);//释放映射区
	if(ret == -1)
	{
		sys_ret("munmap error");
	}
	return 0;
}

mmap函数是创建共享映射,对应还有一个munmap函数,就是释放映射区

二、mmap注意事项

在这里插入图片描述

mmap函数的保险调用方式:
1,fd = open(“文件名”,O_RDWR);
2,mmap(NULL,有效文件大小,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

三、mmap父子进程通信

父子等有血缘关系的进程之间用mmap建立的映射区来完成数据通信时,要再创建映射区时指定对应的标志位参数flags:
MAP_PRIVATE:私有映射,父子进程各自独占映射区
MAP_SHARED:共享映射,父子进程共享映射区

例子👇父进程创建映射区,然后fork子进程,子进程修改映射区内容,然后父进程读取映射区内容,查验是否共享

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

int var = 100;//全局变量

void sys_err(const char *str)
{
	perror(str);
	exit(1);
}
int main(int argc, char *argv[])
{
	//先创建mmap映射,需要打开一个文件
	int *p;//指针类型需要不同场合不同指定
	pid_t pid;
	int fd;
	fd = open("testmmap",O_RDWR|O_CREATE|O_TRUNC,0644);
	if(fd<0)
	{
		perror("open error");
		exit(1);
	}
	unlink("testmmap");//删除临时文件目录项,使之具备被删除条件
	ftruncate(fd,4);//扩展文件
	p = (int *)mmap(NULL,4,PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if(p == MAP_FAILED)
	{
		perror("map error");
		exit(1);
	}
	close(fd);//映射区建立完毕,即可关闭文件

	//开始创建子进程
	pid = fork();
	if(pid == 0)//子进程
	{
		*p =2000;//写共享内存
		var = 1000;
		printf("child, *p = %d, var = %d\n", *p, var); //读共享内存
	}else
	{
		//父进程
		sleep(1);
		printf("parent, *p = %d,var = %d", *p, var);
		wait(NULL);
	int ret = munmap(p,4);
	if(ret == -1)
	{
		perror("munmap error");
		exit(1);
	}
	}
	return 0;
}

结果👇:读时共享,写时复制,var就还是var,写就是写了
在这里插入图片描述

四、无血缘关系进程间mmap通信

一个写进程

//写的一个进程
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/mman.h>

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

void sys_err(const char *str)
{
	perror(str);
	exit(1);
}

int main(int argc, char *argv[])
{
	struct student stu = {10,"xiaoming",18};
	struct student *p;
	int fd;
	open("testmap",O_REWR|O_CREATE|O_TRUNC,0664);
	if(fd == -1)
	{
		sys_err("open error");
	}
	ftruncate(fd, sizeof(stu));
	p = mmap(NULL,sizeof(stu),PROT_READ|PRROT_WRITE,MAP_SHARED,fd,0);
	if(p == MAP_FAILED)
		sys_err("mmap error");
	close(fd);//映射好了就可以关闭文件
		
	while(1)
	{
		memcpy(p, &stu, sizeof(stu));
		stu.id++;
		sleep(1);
	}
	munmap(p, sizeof(stu));
}

同理再一个读进程,只要两个进程都映射到一个内存中就可以进行通信,即两个进程对同一个文件创建映射区

注意:mmap与fifo的区别:

mmap:数据可以重复读取;fifo数据只能一次读取

五、mmap匿名映射:无需依赖文件即可创建映射区

==过了一下没有认真看xX
unlink函数
不需要关于文件的代码了
在这里插入图片描述
??可是它不需要文件的话怎么知道映射到哪里去?
嗷嗷嗷嗷嗷我们的目的是让两个进程进行通信,目的不是去改文件,ok没毛病了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值