Linux的内存共享映射(mmap和munmap)

 

       Linux下的进程间通信也可以使用mmap的内存共享映射来实现,mmap的作用就是把磁盘文件的一部分直接映射到进程的内存中,那么进程就可以直接对该内存文件进行操作,mmap也设置了两种机制:共享和私有,如果是共享映射,那么在内存中对文件进行修改,磁盘中对应的文件也会被修改,相反,磁盘中的文件有了修改,内存中的文件也被修改。如果是私有映射,那么内存中的文件是独立的,二者进行修改都不会对对方造成影响。通过这样的内存共享映射就相当于是进程直接对磁盘中的文件进行读写操作一样,那么如果有两个进程来mmap同一个文件,就实现了进程间的通信。磁盘中的文件通过mmap函数来实现映射,然后通过munmap函数取消映射。先来看一下函数的原型:

#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);

       其中对于mmap来说,有6个参数,第一个参数是你要映射的起始地址,这里一般用NULL,这样系统会在0地址附近随机分配一块内存。第二个参数是所要映射的文件长度。第三个参数是所映射的文件的权限,其中包含(PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE)这四种参数。第四个参数是映射类型,其中包括(MAP_SHARED, MAP_PRIVATE)。第五个参数是文件描述符。第六个参数是偏移量。我们可以看到函数的返回值为void *,那么如果映射成功则会返回映射的首地址,如果出错则返回常数MAP_FAILED。当进程终止时,该进程的映射内存会自动解除,也可以调用munmap解除映射,解除成功返回0,出错返回-1。那么这些参数对应着下图:

        

       对于第三个参数,PROT_EXEC表示映射的这一段可执行,例如映射共享库,PROT_READ表示这一段可读,PROT_WRITE表示这一段可写,PROT_NONE表示这一段不可访问。对于第四个参数,MAP_SHARED表示共享映射,MAP_PRIVATE表示私有映射。最后一个参数偏移量表示要从文件的哪个地方开始映射,应为4096的整数倍。

       下面简单实现通过mmap实现的进程间通信,先看以下写操作的代码:

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

void sys_err(char *s){  // 出错返回函数
	perror(s);
	exit(1);
}

int main(int argc, char *argv[])
{
	if(argc != 2){
		printf("Run error\n");
		exit(1);
	}
	int fd = open(argv[1], O_RDWR | O_CREAT, 0777);
	char *mm;
	int cnt = 1;
	if(fd == -1) 
		sys_err("open");
	if(lseek(fd, 0x1000 - 1, SEEK_SET) == -1)     // 将文件大小变为4096
		sys_err("lseek");
	if(write(fd, "\0", 1) == -1)                  // lseek之后必须要有写操作
		sys_err("write");
	mm = mmap(NULL, 0x1000, PROT_WRITE, MAP_SHARED, fd, 0);
	if(mm == MAP_FAILED)
		sys_err("mmap");
	close(fd);
	while(1){
		sprintf(mm, "Hello %d\n", cnt);
        printf("Write :Hello %d\n", cnt ++);
		sleep(1);
	}
	munmap(mm, 0x1000);
	return 0;
}

       下面是读操作的代码:

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

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

int main(int argc, char *argv[])
{
	if(argc != 2){
		printf("Open error\n");
		exit(1);
	}
	int fd = open(argv[1], O_RDONLY);
	if(fd == -1)
		sys_err("open");
	char *mm = mmap(NULL, 0x1000, PROT_READ, MAP_SHARED, fd, 0);
	close(fd);
	while(1){
		printf("Read :%s", mm);
		sleep(1);
	}
	munmap(mm, 0x1000);
	return 0;
}

       运行结果如下图所示:

           

       由于这只是实现两个进程间的通信,那么对于test文件来说在没有进程运行的时候没有什么作用,所以它可以设置为一个临时文件,所以可以在代码中使用unlink函数,在进程结束以后删除test文件。还有在进行通信时可以将数据封装为一个结构体,通过结构体进行数据的传递。如果在运行中出现Bus error (core dumped)错误,需要考虑共享文件是否有存储空间(也就是说你要mmap一个4096的文件,但实际文件没有4096那么大)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值