0基础学会 mmap内存映射(内附C++代码)

#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);

-功能:将一个文件或者设备的数据映射到内存中

-参数:

         -void *addr:NULL,由内核指定

         -length:要映射的数据长度,这个值不能为0,建议使用文件的长度,获取文件的长度:stat lseek

        -proc:对申请的内存映射区的操作权限

                -PROT_EXEC:可执行的权限

                -PROT_READ:读权限

                -PROT_WRITE:写权限

                -PROT_NONE:没有权限

                要操作映射内存,必须要有读的权限。

                PROT_READ 、PROT_READ|PROT_WRITE

        -flags:

                -MAP_SHARED:映射区的数据会自动和磁盘文件进行同步,进程间通信,必须要设置这个选项

                -MAP_PRIVATE:不同步,内存映射区的数据改变了,对原来的文件

        -fd:需要映射的那个文件的文件描述符

                -通过open得到,open的是一个磁盘文件

                -注意:文件的大小不能为0,open指定的权限不能和prot参数有冲突

                prot:PROT_READ         open 只读/读写

                prot:PROT_READ |PROT_WRITE open:读写

        -offset:偏移量,一般不用。必须指定4K的整数倍,0表示不偏移

        -返回值:返回创建的内存首地址

                失败返回MAP_FAILED,(void *) -1

int mumap(void *addr,size_t length);

        -功能:释放内存映射

        -参数:

                -addr:要释放的内存的首地址

                -length:要释放的内存大小,要和mmap函数中的length参数值一样

       使用内存映射实现进程间通信:

1、有关系的进程(父子进程)

        -还没有子进程的时候

                -通过唯一的父进程,先创建内存映射区

        -有了内存映射区以后,创建子进程

        -父子进程共享创建的内存映射区

2、没有关系的进程间通信

        -准备一个大小不是0的磁盘文件

        -进程1 通过磁盘文件创建内存映射区

                -得到一个操作这块内存的指针

        -进程2 通过磁盘文件创建内存映射区

                -得到一个操作这块内存的指针

        -使用内存映射区通信

注意:内存映射区通信,是非阻塞

首先我们写一个有父子关系的内存映射

这里需要注意的点:一定要提前创建一个映射区,例如test.txt,并且这个映射区的大小必须大于0,否则没有办法往里面添加数据。(创建完之后可以在test.txt里写上几个字来扩充其大小。)

  1 #include <stdio.h>
  2 #include <wait.h>
  3 #include <sys/mman.h>
  4 #include <unistd.h>
  5 #include <stdlib.h>
  6 #include <sys/stat.h>
  7 #include <sys/types.h>
  8 #include <fcntl.h>
  9 #include <string.h>
 10 int main()
 11 {
 12         int fd=open("test.txt",O_RDWR);//1、打开一个文件
 13         int size=lseek(fd,0,SEEK_END);//2、获取文件的大小,从fd这个文件的起始位置到文件末尾
 14         void *ptr=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//3、一定要在创建父子进程之前创建内存映射区
 15         if(ptr==MAP_FAILED)//如果出现错误,类似于其他函数返回-1
 16         {
 17                 perror("mmap");
 18                 exit(0);
 19         }
 20         //4、创建子进程
 21         pid_t pid=fork();
 22         if(pid>0)
 23         {
 24                 wait(NULL);//回收子进程
                    //父进程
 25                 char buf[64];
 26                 strcpy(buf,(char *)ptr);//将ptr中的数据复制到buf中
 27                 printf("read data:%s\n",buf);
 28 
 29         }
 30         else if(pid==0)
 31         {        //子进程
 32                 strcpy((char *)ptr,"你好呀,小朋友!");
 33         }
 34         munmap(ptr,size);//将前面创建的内存映射区解除掉
 35         return 0;
 36 }

输出结果为:

 补充:如果想把“读”和“写”分开操作也是可以的,这正好是没有关系的进程间通信,其实是非常简单的,只要把本程序中的父子进程分别写到两个文件中就可以了,这个我就不操作了,可以留作课下作业去完成。

还有,你写到两个文件中后,本程序中的前三步依然是要有的,切记!

另外,内存映射还有几点注意事项:

(1)如果对mmap的返回值(ptr)做++操作(ptr++),munmap是否能够成功?

void *ptr=mmap();

ptr++;//可以对其将进行++操作

munmap(ptr,len)//错误,要保存地址,释放的应该是源地址,而源地址已经发生了变化

(2)如果open时O_RDONLY,mmap时prot参数指定PROT_READ | PROT_WRITE会怎么样?

错误,返回MAP_FAILED

(3)如果文件偏移量为1000会怎样?

偏移量必须是4K的整数倍,否则会返回MAP_FAILED

(4)mmap什么情况下会调用失败?

-第二个参数:length=0;

-第三个参数:prot

        -只指定了写权限

               -prot PROT_READ | PROT_WRITE

        第五个参数fd 通过open函数指定的O_RDONLY或者O_WRONLY。

(5)可以open的时候O_CREAT一个新文件来创建映射区嘛?

可以的,但是创建的文件的大小如果为0的话,肯定不行

可以对新的文件进行扩展

        -lseek()

        -truncate()

(6)mmap后关闭文件描述符,对mmap映射有没有影响?

int fd=open("XXX");

mmap(,,,,fd,,);

close(fd);

映射区还存在,创建映射区的fd被关闭,没有任何影响

(7)对ptr越界操作会怎么?

void *ptr=mmap(NULL,100,,,);

越界操作的是非法的内存->段错误。

记住吧!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值