内存映射简单使用

本文介绍了C语言在Linux环境下如何进行内存映射,包括常用方法、实例演示和注意事项。通过设置不同的参数,如PROT_READ、PROT_WRITE、MAP_SHARED和MAP_PRIVATE,实现对文件的读写,并通过映射内存来共享或私有化数据。同时强调了在内存映射过程中需要注意文件大小与映射存储区大小的关系,避免数据丢失或触发SIGBUS信号导致进程终止。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内存映射

1.常用方法
   #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);
成功,返回存储器起始地址;失败,返回MAP_FAILED

addr:指定映射存储区的起始地址,通常设置为0,表示由系统选择起始地址。

length:存储地址大小。

prot:映射存储区的保护要求。PROT_READ,存储器可读;PROT_WRITE,存储区可写;PROT_EXEC,存储区可执行;PROT_NONE,存储区不可访问。保护要求不能超过文件open模式访问权限。

flags:MAP_SHARED,表示对映射区的修改,相当于对文件的修改;MAP_PRIVATE,表示对映射区的修改,只是对文件副本的修改,原文件不变。一般设置flags为MAP_SHARED。

fd:映射存储区对应的文件。

offset:偏移量。

2.实例

1.创建两个进程,使用映射内存读写文件中的数据。

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

#define MEM_SIZE 1024
#define PATH "/tmp/out"

int main(int argc, char const *argv[])
{
    void *ptr;
    int fd;
    pid_t pid;
    struct stat stat_buf;
    if(argc < 2){
        fprintf(stderr, "argv error.\n");
        exit(1);
    }
    if ((fd = open(PATH, O_CREAT | O_RDWR, 0660)) < 0)
    {
        perror("open()");
        exit(1);
    }
    if(fstat(fd, &stat_buf) < 0){
        perror("fstat()");
        exit(1);
    }
    //被映射的文件如果大小小于映射存储区的大小,对存储区的修改超过了文件大小,会导致数据丢失。
    //新创建的文件,大小为0,不对文件进行扩展,对相关存储区的第一次引用时会产生SIGBUS信号。
    if(stat_buf.st_size < MEM_SIZE){
        ftruncate(fd, MEM_SIZE);
    }
    ptr = mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (ptr == MAP_FAILED)
    {
        perror("mmap()");
        exit(1);
    }
    close(fd);
    pid = fork();
    if (pid < 0)
    {
        perror("fork()");
        exit(1);
    }
    if (pid == 0)
    { //child
        memset(ptr, 0, MEM_SIZE);
        strcpy(ptr, argv[1]);
    }
    else
    { //parent
        wait(NULL);
        puts(ptr);
    }
    munmap(ptr, MEM_SIZE);
    exit(0);
}

falgs为MAP_SHARED,执行结果:
shbj@ubuntu:~/develop/workspace/c/hio$ ./mmap1 "Hello world"
Hello world
shbj@ubuntu:~/develop/workspace/c/hio$ cat /tmp/out
Hello worldshbj@ubuntu:~/develop/workspace/c/hio$ ./mmap1 "Good morning"
Good morning
shbj@ubuntu:~/develop/workspace/c/hio$ cat /tmp/out
Good morningshbj@ubuntu:~/develop/workspace/c/hio$ 
    
falgs为MAP_PRIVATE,执行结果:    
shbj@ubuntu:~/develop/workspace/c/hio$ cat /tmp/out
Good morningshbj@ubuntu:~/develop/workspace/c/hio$ ./mmap1 "Hello world"
Good morning
shbj@ubuntu:~/develop/workspace/c/hio$ cat /tmp/out
Good morningshbj@ubuntu:~/develop/workspace/c/hio$ 

对比两组执行结果,可以看出flags参数为MAP_SHARED,对映射区的进行修改,对应的文件也修改了;MAP_PRIVATE,对映射区进行修改,映射区中的内容改变了,但是原文件中的内容没有改变。

3.注意
  1. 被映射的文件如果大小小于映射存储区的大小,对存储区的修改超过了文件大小,会导致数据丢失。
  2. 如果文件大小为0(如新建的文件),不对文件进行拓展,对相关存储区的第一次引用时会产生SIGBUS信号,导致进程终止。
  3. 所以使用内存映射时,要先调用fstat()函数获取到文件大小,再根据文件大小是否为0或小于存储区的大小,判断是否调用ftruncate()函数对文件进行扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值