内存控制mmap的原型和使用方法

函数原型

// 创建内存映射区
#include <sys/mman.h>
void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);

// 释放内存映射区
int munmap(void *addr, size_t len); 

形参:

  • addr:指定映射区域的首地址。通常传入NULL,表示让系统自动分配
  • length: 共享内存映射区的大小(小于等于文件的实际大小)
  • prot:共享内存映射区的读写属性, PROT_READ, PROT_WRITE
    • PROT_READ | PROT_WRITE 读写权限
  • flags:标注共享内存的共享属性。MAP_SHARED/ MAP_PRIVARE
  • fd:用于创建共享内存映射区那个文件描述符
  • offset:默认是0,表示映射文件全部。偏移位置 4K的整数倍

返回值:

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

mmap的使用例子

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


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

void my_mmap(){
    char *p = NULL;
    int fd;

    //  需要先打开一个文件
    fd = open("testmap", O_RDWR|O_CREAT|O_TRUNC, 0644);
    if (fd==-1){
        sys_err("open error");
    }
    // 需要拓展文件大小, 这样可以拓展文件大小为11
    lseek(fd, 10, SEEK_END);
    write(fd, "\0", 1);

    //  获取文件长度
    off_t len = lseek(fd, 0, SEEK_END);

    // truncate,可以直接拓展文件大小
    ftruncate(fd, 10);  // 需要写权限才可以拓展文件大小

    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);   // 读操作


    // 释放mmap空间
    int ret = munmap(p, len);
    if (ret==-1){
        sys_err("munmap error");
    }

		close(fd);
}


int main() {
    my_mmap();
}

mmap的注意事项

  1. 用于创建映射区的大小为0, 实际指定非0大小创建映射区,会出现总线错误
  2. 用于创建映射区的文件大小为0, 实际制定0大小创建映射区,出无效参数
  3. 用于创建映射区的文件读写属性为,只读。映射区属性为读,写。出"无效参数"
  4. 创建映射区,需要read权限。因此,mmap的权限应该小于等于open权限。
  5. 文件描述符fd,在mmap创建映射区完成后即可关闭,后续访问文件,用地址访问
  6. offset必须是4096的整数倍
  7. 对申请的内存,不能越界访问。
  8. p++会直接修改p的内存地址,所有在释放的时候回出错,munmap释放的地址,必须是mmap返回的地址
  9. mmap的返回值必须要进行检查,因为非常容易出错
  10. 映射访问权限为”私有“MAP_PRIVATE, 对内存所做的所有修改,只在内存有效, 不会反应到物理磁盘上。
  11. 映射区访问权限为”私有“MAP_PRIVATE,只需要open文件时,有读权限,用于创建映射区即可。

mmap的保险调用方式

  1. open的时候指定O_RDWR
  2. mmap(NULL, 有效文件大小, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

mmap父子进程进行通信

  1. 先创建映射区。open打开
  2. flags需要使用MAP_SHARED进行共享映射
  3. 父进程要先进行创建映射区之后在fork创建子进程
  4. 一个进程读,一个进程写

无血缘关系的进程通信

  1. 两个进程,打开同一个文件,创建映射区
  2. 指定flags为MAP_SHARED
  3. 一个进程写入,一个进程读出
  4. 注意一点:无血缘关系进程之间通信,mmap:数据可以重复读取,fifo数据只可以读取一次

匿名映射

  • 匿名映射flag设置为MAP_ANONYMOUS
  • 不需要创建fd文件对象
  • len想要多长给多长
  • fd传入-1
  • 如果呢米有匿名flags的选项
    • /dev/zero --> "\0" ,随便取值多少
    • /dev/null ----> 随便怎么写入
posted @ 2020-03-20 08:47  FANDX  阅读(596)  评论(0编辑  收藏  举报