进程通信之内存映射区(mmap函数)


父子进程共享:
1、文件描述符
2、内存映射区

  • 内存映射区不仅可以进行有血缘关系之间的进程通信,还可以进行无血缘关系之间的进程通信。
  • 内存映射区分为匿名映射区和有名映射区。

一般而言,父子之间进程通信通过匿名映射区就可以实现,不用通过文件进行映射。

无血缘关系之间进程通信通过文件中继进行映射。因为打开同一个文件,其在不同进程中产生的不同的文件描述符,通过对该文件描述符进行映射可以得到相同的内存映射区地址。
因此,文件只是作为中继者的作用。

创建内存映射区

  • 函数原型
void *mmap(
    void *adrr,      //映射区首地址,传NULL
    size_t length,   //映射区的大小,不能为0,文件多大,length多大
    int port,        //映射区权限,PORT_EXEC、
                                  PORT_READ -- 映射区必须要有读权限
                                  PORT_WRITE、
                                  PORT_NONE
    int flags,       //标志位参数,MAP_SHARED -- 修改了内存数据会同步到磁盘
                                  MAP_PRIVATE --修改了内存数据不会同步到磁盘
    int fd,          //文件描述符,被映射的文件对应的文件描述符,通过open()得到
    off_t offset,    //映射文件的偏移量。映射的时候文件指针的偏移量,必须是4k的整数倍
);
  • 返回值:映射区的首地址–调用成功;返回(void *)-1 – 调用失败

释放内存映射区

函数原型

int munmap(
    void *addr,    //mmap的返回值,映射区的首地址 
    size_t length  //映射区的首地址
);

创建匿名内存映射区

匿名内存映射区不存在文件描述符,但是多一个标志位,MAP_ANON。这个标志位意思是:创建一个匿名的共享的映射区。

void* res = mmap(NULL,4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);

无血缘关系进程进行通讯

  • 写端
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
int main()
{
    int fd = open("/home/junkle/桌面/wxt.txt", O_RDWR | O_CREAT);
    ftruncate(fd, 4096);
    long len = lseek(fd, 0, SEEK_END);
    void* res = mmap(NULL, (size_t)len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(res == MAP_FAILED){return -1;}
    close(fd);
    //下面进行无血缘关系之间进程通讯
    while (1) {
        strcpy((char*)res + 1024, "你好啊,我是西大大" );
        sleep(2);
    }
}
  • 读端
```cpp
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>

void main()
{
    int ret = access("/home/junkle/桌面/wxt.txt",F_OK);
    if(ret == -1) {printf("error\n");return;}
    int fd = open("/home/junkle/桌面/wxt.txt", O_RDONLY);
    ftruncate(fd, 4096);
    long len = lseek(fd, 0, SEEK_END);
    void* res = mmap(NULL, 4096, PROT_READ, MAP_SHARED, fd, 0);
    close(fd);
    while(1)
    {
        printf("%s\n", (char*)res + 1024);
        sleep(1);
    }

}

总结

内存映射区主要是将磁盘文件映射到内存中,但是又由于同一个文件的内存映射区是一样的。因此,可以在两个进程中打开相同的文件并且访问该文件的内存映射区来进行通信。
需要注意的是:通过内存映射区进行通信不会像管道那样本身具有阻塞的功能。这个只是普通的读写内存的操作,由于直接操作内存,效率比管道要高。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值