Linux系统编程——共享内存映射(进程间通信)

mmap函数

1.函数原型

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

参数:

  • addr:指定映射区的首地址。通常传NULL,表示让系统自动分配
  • length:共享内存映射区的大小
  • prot:共享内存映射区的读写属性。PROT_READ、PROT_YRITE、PROT_READ、PROT__RITE
  • flags:标注共享内存的共享属性。MAP_SHARED、IAP_PRIVATE
  • fd:用于创建共亨内存映射区的那个文件的文件描述符。
  • offset:偏移位置。需是4的整数倍。

返回值:

  • 成功:映射区的首地址。
  • 失败:MAP_FAILED , errno

2.建立映射区

  • int manmap(void *addr,size_t length);
    释放映射区。
  • addr: mmap的返回值
  • length:大小
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>

void sys_err(const char *str)
{
    
    
	perror(str);
	exit(1);
}
int main(int argc,char *argv[])
{
    
    
	char *p = NULL;
	int fd;
	fd = open("testmap",O_RDWR|O_CREAT|O_TRUNC,0664);
	if(fd == -1)
	{
    
    
		sys_err("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)
	{
    
    
		sys_err("mmap error");
	}
	//使用p对文件进行读写操作
	strcpy(p,"hello mmap");
	printf("-----%s\n",p);
	int ret = munmap(p,len);
	if(ret == -1)
	{
    
    
		sys_err("munmap error");
	}
	return 0;
}

3.注意事项

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

4.父子进程间mmap通信

  1. 父进程先创建映射区。open ( O_RDWR)map( MAP_SHARED ) ;
  2. 指定MAP_SHARED权限
  3. fork()创建子进程。
  4. 一个进程读,另外一个进程写。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
int var = 200;
void sys_err(const char *str)
{
    
    
	perror(str);
	exit(1);
}
int main(int argc,char *argv[])
{
    
    
	int *p;
	pid_t = pid;
	int fd;
	fd = open("testmap",O_RDWR|O_CREAT|O_TRUNC,0664);
	if(fd == -1)
	{
    
    
		sys_err("open error");
	}
	ftruncate(fd,20);
	p = (int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	if(p == MAP_FAILED)
	{
    
    
		sys_err("mmap error");
	}
	close(fd);			//映射区创建完毕,即可关闭文件
	pid = fork();		//创建子进程
	if(pid == 0){
    
    		
		*p = 2000;		//写共享内存
		var = 1000;
	}else{
    
    				//父进程操作
		sleep(1);
		printf("parent,*p = %d,var = %d\n",*p,var);//读共享内存,var:读时共享,写时复制
		wait(NULL);
		int ret = munmap(p,len);//释放映射区
		if(ret == -1)
		{
    
    
			sys_err("munmap error");
		}	
	}
	return 0;
}

4.无血缘关系进程间mmap通信

  • 两个进程打开同一个文件,创建映射区。
  • 指定f1ags 为 MAP_SHARED。
  • 一个进程写入,另外一个进程读出。

【注意】﹔无血缘关系进程间通信。

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

写进程:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
struct student{
    
    
	int id;
	char name[25];
	int age;
};
void sys_err(const char *str)
{
    
    
	perror(str);
	exit(1);
}
int main(int argc,char *argv[])
{
    
    
	struct student stu = {
    
    110,"xiaom",18};
	struct student *p;
	int fd;
	fd = open("testmap",O_RDWR|O_CREAT|O_TRUNC,0664);
	if(fd == -1)
	{
    
    
		sys_err("open error");
	}
	ftruncate(fd,sizeof(stu));
	p = (struct student *)mmap(NULL,sizeof(stu),PROT_READ|PROT_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));
	
	return 0;
}

读进程:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
struct student{
    
    
	int id;
	char name[25];
	int age;
};
void sys_err(const char *str)
{
    
    
	perror(str);
	exit(1);
}
int main(int argc,char *argv[])
{
    
    
	struct student stu;
	struct student *p;
	int fd;
	fd = open("testmap",O_RDWR|O_CREAT|O_TRUNC,0664);
	if(fd == -1)
	{
    
    
		sys_err("open error");
	}
	p = (struct student *)mmap(NULL,sizeof(stu),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	if(p == MAP_FAILED)
	{
    
    
		sys_err("mmap error");
	}
	close(fd);			//映射区创建完毕,即可关闭文件
	while(1){
    
    
		printf("id = %d,name = %s,age = %d",p->id,p->name,p->age);
		sleep(1);
	}
	munmap(p,sizeof(stu));
	
	return 0;
}

附:文件用于进程间通信

一个进程对文件读,另一进程对文件写

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Strive_LiJiaLe/article/details/128635064
今日推荐