进程间通信:内存映射

目录

基本概念

相关系统调用

使用内存映射进程通信:(是非阻塞通信。)

父子进程通过内存映射通信;

内存映射注意事项

匿名映射


基本概念

将磁盘文件映射到内存,用户修改内存就可以直接修改磁盘文件。(修改内存快很多,改磁盘很慢)。


相关系统调用

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

            映射长length(非0)的磁盘文件到addr(nullptr则自动选择一个)。
            stat lseek可以获取文件长度(当小于分页大小,会至少指定一个分页大小)
            prot:对申请的内存映射区的操作权限。 PROT_EXEC  PROT_WRITE PROT_READ  PROT_NONE       要操作,必须有读的权限
            flags:MAP_SHARED 映射区数据会自动和磁盘文件同步,进程通信必须设置
                     MAP_PRIVATE 不同步,映射区修改后,创建一个新文件
            fd:open()得到的映射文件的fd,大小不能为0. open指定权限与prot不能冲突

            offset:偏移量,必须是4k的整数倍,一般不偏移,置0.、

            成功返回创建的内存的首地址 失败返回MAP_FAILED   (void*) -1;

  int munmap(void *addr, size_t length); 释放内存映射 数值同上。


使用内存映射进程通信:(是非阻塞通信。)

        1 有关系的进程: 先映射,再fork()  父子进程共享创建的内存映射区

        2 没有关系:准备一个大小非0的磁盘文件,

                              进程1以此创建内存映射区,得到操作该内存的指针,

                              进程2也以此创建内存映射区,得到操作该内存的指针,  两个以此通信。

父子进程通过内存映射通信;

#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{ 
   
    int ret=open("test.txt",O_RDWR);
    int size=lseek(ret,0,SEEK_END);
 //内存映射
    void* ptr=mmap(nullptr,size,PROT_READ|PROT_WRITE,MAP_SHARED,ret,0);
    if(ptr==MAP_FAILED)
    {
        perror("mmap:");
        exit(0);
    }
    pid_t pid=fork();

    if(pid>0)
    {//父进程
        wait(NULL);
        char buf[64];
        strcpy(buf,(char*)ptr);
        std::cout<<"parent read: "<<buf<<" "<<getpid()<<std::endl;
    }
    else if(pid==0)
    {
        //子进程
        strcpy((char*)ptr,"today is a good day");
    }
    std::cout<<"i am here "<<getpid()<<"\n";
    munmap(ptr,size);
}

内存映射注意事项

1 mmap返回的ptr,可以++,但是++后munmap(ptr,len)会发生错误。 所以++前要先保存一份。

open指定权限与prot不能冲突,MAP_FAILED

3 文件偏移量必须是4k整数倍,否则返回MAP_FAILED

磁盘文件大小非0

5 open时可以O_CREAT创建新文件,但为了文件大小非0,需要对其扩展,lseek/ftruncate。

  int ret=open("lseek.txt",O_CREAT|O_RDWR,0664);

  lseek(ret,20,SEEK_END);

  char *wrbuf= "hjhk";

  write(ret,wrbuf,strlen(wrbuf));    扩展并写入文件大小才能生效
或者//
   ftruncate(ret,20);
   //truncate("lseek.txt",20)

6 mmap后关闭fd,对mmap无影响。 

7 void*ptr=mmap()   ptr越界操作的时非法内存,会产生段错误(当程序试图访问不允许访问内存位置,或试图以不允许的方式访问内存位置(例如尝试写入只读位置,或覆盖部分操作系统)时会发生段错误)。

8 可以用来实现文件复制。旧文件和要复制的文件分别映射后, memcpy(ptr1,ptr,len)进行内存复制。

匿名映射

不需要文件实体进行内存映射。可用于父子进程通信。 flag设置MAP_ANONYMOUS   fd=-1;

 void* ptr=mmap(nullptr,4096,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
   

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值