内存映射

 

/*
    内存映射:
        是将磁盘文件数据映射到内存,用户通过修改内存就能修改磁盘文件


        #include <sys/mman.h>

        void *mmap(void *addr, size_t length, int prot, int flags,
                    int fd, off_t offset);

            功能:将一个文件或设备的数据映射到内存中
            参数:
                addr:NULL,由内核决定
                length:要映射的数据的长度,值不能为0,建议使用文件的长度
                        获取文件的长度:stat lseek
                prot:对申请的内存映射区的操作权限
                    PROT_EXEC  Pages may be executed.

                    PROT_READ  Pages may be read.

                    PROT_WRITE Pages may be written.

                    PROT_NONE  Pages may not be accessed.
                    要操作映射内存,必须要有读权限,通过|连接权限
                flags:
                    MAP_SHARED:映射区的数据会自动和磁盘文件进行同步,进程间通信必须要设置这个选项
                    MAP_PRIVATE:不同步,写时复制
                fd:
                    需要映射文件的文件描述符
                    通过open得到
                    注意:文件大小不能为0,open权限不能于prot参数有冲突,open >= prot
                offset:
                    偏移量,一般不用,必须指定的是4k的整数倍,0表示不偏移
            返回值:
                成功:返回创建的内存首地址
                失败:返回MAP_FAILED,(void *) -1

        int munmap(void *addr, size_t length);
            功能:释放内存映射
            参数:
                addr:要释放的内存的首地址
                length:要释放的内存大小,要和mmap函数中的length值相同

*/

/*
    使用内存映射实现进程间通信:
    1、有关系的进程(父子进程)
        还没有子进程的时候
            通过唯一的父进程,先创建内存映射区
        有了内存映射区以后,创建子进程
        父子进程共享创建的内存映射区
    2、没有关系的进程间通信
        准备一个大小不是0的磁盘文件
        进程1 通过磁盘文件创建内存映射区
              得到一个操作这块内存的指针
        进程2 通过磁盘文件创建内存映射区
              得到一个操作这块内存的指针
        使用内存映射区通信
    注意:内存映射区通信,是非堵塞的



*/

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

int main()
{
    int fd = open("test.txt", O_RDWR | O_CREAT, 0777);
    int size = lseek(fd, 0, SEEK_END);
    //               默认   文件大小   与打开文件的权限相同 同步或非同步 默认 默认
    void *shared_addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(shared_addr == MAP_FAILED)
    {
        perror("mmap error");
        exit(-1);
    }



    int fork_flag = fork();
    if(fork_flag == 0)
    {
        strcpy((char *)shared_addr, "Hello World");
    }
    else
    {
        sleep(1);
        char str[1024] = {0};
        strcpy(str, (char *)shared_addr);
        printf("recve a info: %s\n", str);
    }

    munmap(shared_addr, size);
    close(fd);

    return 0;

}

 

 

# 内存映射实现文件拷贝

/*
    使用内存映射实现文件拷贝
        1、对原始文件进行内存映射
        2、创建一个新文件(拓展该文件) 
            int truncate(const char *path, off_t length);
            
            off_t lseek(int fd, off_t offset, int whence);
            拓展完 写一下 writ(fd, " ", 1);
        3、把新文件的数据映射到内存中
        4、通过内存拷贝将第一个文件的内存数据拷贝到新的文件内存中
            memcpy()
        5、释放资源



*/

 

 

# 匿名映射

/*
    匿名映射
        没有文件实体,用于存在关系的进程之间
        prot追加MAP_ANONYMOUS
        文件描述符-1即可
*/

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

int main()
{   
    int len = 4096;
    void *shared_addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    if(shared_addr == MAP_FAILED)
    {
        perror("mmap error");
        exit(-1);
    }

    int fork_flag = fork();
    if(fork_flag == 0)
    {
        strcpy((char *)shared_addr, "HELLO WORLD");
    }
    else
    {
        sleep(1);
        printf("%s\n", (char *)shared_addr);
        wait(NULL);
    }

    munmap(shared_addr, len);

    return 0;
}

 

posted @ 2023-04-29 15:15  WTSRUVF  阅读(20)  评论(0编辑  收藏  举报