• 第2章 Linux多进程开发 2.18 内存映射


    内存映射:可以进行进程间的通信
    在这里插入图片描述

    1.如果对mmap的返回值(ptr)做++操作(ptr++), munmap是否能够成功?
    void * ptr = mmap(…);
    ptr++; 可以对其进行++操作
    munmap(ptr, len); // 错误,要保存地址

    2.如果open时O_RDONLY, mmap时prot参数指定PROT_READ | PROT_WRITE会怎样?
    错误,返回MAP_FAILED
    open()函数中的权限建议和prot参数的权限保持一致。

    3.如果文件偏移量为1000会怎样?
    偏移量必须是4K的整数倍,返回MAP_FAILED

    4.mmap什么情况下会调用失败?
    - 第二个参数:length = 0
    - 第三个参数:prot
    - 只指定了写权限
    - prot PROT_READ | PROT_WRITE
    第5个参数fd 通过open函数时指定的 O_RDONLY / O_WRONLY

    5.可以open的时候O_CREAT一个新文件来创建映射区吗?
    - 可以的,但是创建的文件的大小如果为0的话,肯定不行
    - 可以对新的文件进行扩展
    - lseek()
    - truncate()

    6.mmap后关闭文件描述符,对mmap映射有没有影响?
    int fd = open(“XXX”);
    mmap(,fd,0); // 0 是偏移量
    close(fd);
    映射区还存在,创建映射区的fd被关闭,没有任何影响。

    7.对ptr越界操作会怎样?
    void * ptr = mmap(NULL, 100,); //映射100个数据
    4K
    越界操作操作的是非法的内存 (野地址)-> 段错误

    使用内存映射实现文件拷贝:

    在这里插入图片描述

    // 使用内存映射实现文件拷贝的功能
    /*
        思路:
            1.对原始的文件进行内存映射
            2.创建一个新文件(拓展该文件)
            3.把新文件的数据映射到内存中
            4.通过内存拷贝将第一个文件的内存数据拷贝到新的文件内存中
            5.释放资源
    */
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main() {
    
        // 1.对原始的文件进行内存映射
        int fd = open("english.txt", O_RDWR);
        if(fd == -1) {
            perror("open");
            exit(0);
        }
    
        // 获取原始文件的大小  表示从末尾开始偏移0 
        int len = lseek(fd, 0, SEEK_END);
    
        // 2.创建一个新文件(拓展该文件)
        int fd1 = open("cpy.txt", O_RDWR | O_CREAT, 0664);
        if(fd1 == -1) {
            perror("open");
            exit(0);
        }
        
        // 对新创建的文件进行拓展
        truncate("cpy.txt", len);
        write(fd1, " ", 1);
    
        // 3.分别做内存映射
        void * ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        void * ptr1 = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd1, 0);
    
        if(ptr == MAP_FAILED) {
            perror("mmap");
            exit(0);
        }
    
        if(ptr1 == MAP_FAILED) {
            perror("mmap");
            exit(0);
        }
    
        // 内存拷贝
        memcpy(ptr1, ptr, len);
        
        // 释放资源
        munmap(ptr1, len);//谁后打开的先释放,因为后打开的可能依赖先打开的
        munmap(ptr, len);  
    
        close(fd1);  //关闭文件描述符
        close(fd);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    在这里插入图片描述

    匿名函数:

    /*
        匿名映射:不需要文件实体进程一个内存映射  只能用在有关系的进程(如父子进程)
    */
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main() {
    
        // 1.创建匿名内存映射区
        int len = 4096;
        void * ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);   //MAP_SHARED:对数据操作 会更改内容
        if(ptr == MAP_FAILED) {
            perror("mmap");
            exit(0);
        }
    
        // 父子进程间通信
        pid_t pid = fork();   //创建子进程
    
        if(pid > 0) {
            // 父进程
            strcpy((char *) ptr, "hello, world");
            wait(NULL);   //wait 回收子进程的资源
        }else if(pid == 0) {
            // 子进程
            sleep(1);
            printf("%s\n", (char *)ptr);
        }
    
        // 释放内存映射区
        int ret = munmap(ptr, len);
    
        if(ret == -1) {
            perror("munmap");
            exit(0);
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述

  • 相关阅读:
    【Python 千题 —— 基础篇】浮点数转为整数
    【Nginx】MACOS 安装与部署
    记录软考学习
    Matlab:使用分类数组的好处
    金仓数据库KingbaseES数据库管理员指南--15.4. 视图、同义词和序列的数据字典视图
    20个Golang片段让我不再健忘
    C++技能系列( 9 ) - 如何实现线程池【详解】
    想学嵌入式开发,薪资怎么样?
    【前端知识】Node——使用fs模块对文件、文件夹的操作
    傅里叶变换在图像处理中的应用
  • 原文地址:https://blog.csdn.net/weixin_46716100/article/details/132585557