Linux系统编程之进程间通信二:内存映射区

2023-05-16

1 内存映射区

1.1mmap函数

函数功能

  • 创建内存映射
  • 将磁盘文件的数据映射到内存中,通过修改内存就能修改磁盘文件

函数原型

mmap函数原型

  • length:大小为4K的倍数,且不能为0。
    • 一般文件多大,映射区的大小就指定为多大
  • prot
    • PROT_READ:映射区必须要有读权限
    • PROT_WRITE
    • 读写权限是:PROT_READ|PROT_WRITE
  • flags
    • MAP_SHARED:修改了内存数据同步到磁盘
    • MAP_PRIVATE:修改了内存数据不会同步到磁盘
  • fd:要映射的文件的fd。通过open()函数得到
  • offset:映射的时候文件指针的偏移量
    • 必须是4K的整数倍
    • 一般指定为0

返回值

  • 调用成功返回映射区的首地址
  • 调用失败返回MAP_FAILED宏(-1)

1.2 munmap函数

函数作用

  • 释放内存映射区

函数原型

int munmap(void* addr,size_t length);

  • 参数

    addrmmap的返回值,映射区的首地址

    lengthmmap的第二个参数,映射区的大小

  • 返回值

    失败返回-1

2 有血缘关系进程之间的通信

有名内存映射区(借助文件)

通过在内存中创建文件的映射区实现两个进程间通过该映射区通信
A进程写B进程读,当A进程写的东西比较多时可能会出现A没写完,B已经读完了

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<sys/mman.h>
int main(){
    int fd = open("hello",O_RDWR);
    if(fd == -1){
        perror("文件打开失败");
        exit(1);
    }
    //计算文件大小
    int len = lseek(fd,0,SEEK_END);
    //创建内存映射区
    void* ptr = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    if(ptr == MAP_FAILED){
        perror("文件映射区创建失败");
        exit(2);
    }
    //创建子进程,进行进程间通信
    pid_t pid = fork();
    if(pid == -1){
        perror("子进程创建失败");
        exit(3);
    }else if(pid == 0){
        //子进程写,父进程读
        strcpy((char*)ptr,"写的内容\n");
    }else{
        //父进程读
        printf("%s",(char*)ptr);
        wait(NULL);
    }
    //释放内存映射区,关闭文件
    munmap(ptr,len);
    close(fd);
    return 0;
}

上段代码文件”hello“的作用很小,所以有了下段创建匿名内存映射区的方法

匿名内存映射区

与上段代码的差别

  • 没有“hello"文件,内存映射区的大小也不是文件的大小
  • 直接指定创建的内存映射区的大小
  • 修改mmap函数的个别参数
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<sys/mman.h>
int main(){
    //直接指定内存映射区的长度
    int len = 4096;
    //创建内存映射区
    void* ptr = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
    if(ptr == MAP_FAILED){
        perror("文件映射区创建失败");
        exit(2);
    }
    //创建子进程,进行进程间通信
    pid_t pid = fork();
    if(pid == -1){
        perror("子进程创建失败");
        exit(3);
    }else if(pid == 0){
        //子进程写,父进程读
        strcpy((char*)ptr,"写的内容\n");
    }else{
        //父进程读
        printf("%s",(char*)ptr);
        wait(NULL);
    }
    //释放内存映射区,关闭文件
    munmap(ptr,len);
    return 0;
}

3 没有血缘关系进程之间的通信

  • 不能使用匿名映射区
  • 只能借助磁盘文件创建映射区
  • 不阻塞
  • 因为数据在内存映射区,所以数据是可以重复读的
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<sys/mman.h>
int main(){
    int fd = open("hello",O_RDWR|O_CREAT,0666);
    if(fd == -1){
        perror("打开文件失败");
        exit(1);
    }
    ftruncate(fd,4096);
    //计算出文件长度,用来指定开辟的映射区大小
    int len = lseek(fd,0,SEEK_END);
    //创建内存映射区
    void* ptr = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    if(ptr == MAP_FAILED){
        perror("映射区创建失败");
        exit(2);
    }
    while(1){
        printf("%s",(char*)ptr);
        sleep(1);
    }

    //释放内存映射区
    uunmap(ptr,len);
    //关闭文件
    close(fd);
    return 0;
}

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<sys/mman.h>
#include<sys/types.h>
int main(){
    int fd = open("hello",O_RDWR|O_CREAT,0666);
    if(fd == -1){
        perror("打开文件失败");
        exit(1);
    }
    ftruncate(fd,4096);
    //计算出文件长度,用来指定开辟的映射区大小
    int len = lseek(fd,0,SEEK_END);
    //创建内存映射区
    void* ptr = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    if(ptr == MAP_FAILED){
        perror("映射区创建失败");
        exit(2);
    }
    char *buf = "没有血缘关系的进程间通信\n";
    while(1){
        strcpy(ptr,buf);
        sleep(4);
    }

    //释放内存映射区
    uunmap(ptr,len);
    //关闭文件
    close(fd);
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux系统编程之进程间通信二:内存映射区 的相关文章

  • @PathVariable注解的用法和作用

    64 PathVariable注解的用法和作用 64 PathVariable 映射 URL 绑定的占位符 通过 64 PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中 URL 中的 xxx 占位符可以通过
  • 最新虚拟机中Ubuntu18.04安装教程(傻瓜教程)

    1 文件和软件下载 下载Ubuntu18 04文件 可以直接点下方的链接下载 Ubuntu18 04安装链接 下载VMware Workstation 笔者这边使用的是VMware Workstation15 5pro xff0c 大家也可
  • optimizer优化器详解

    在机器学习中 xff0c 优化器 xff08 optimizer xff09 是一种用于更新模型参数以最小化训练误差的算法 它可以将损失函数的梯度作为输入 xff0c 并根据该梯度调整模型参数的值 常见的优化器算法包括随机梯度下降 xff0
  • Java创建多线程的四种方式

    一 继承Thread类 1 创建一个继承于Thread类的子类 2 重写Thread类的run gt 将此线程执行的操作声明在run 中 3 创建Thread类的子类的对象 4 通过此对象调用start 启动当前线程 调用当前线程的run
  • MySQL基础

    本单元目标 一 为什么要学习数据库 二 数据库的相关概念 DBMS DB SQL 三 数据库存储数据的特点 四 初始MySQL MySQL产品的介绍 MySQL产品的安装 MySQL服务的启动和停止 MySQL服务的登录和退出 MySQL的
  • Thread类中的常用方法

    Thread类中的常用方法 xff08 学习总结 xff09 xff1a 序号函数作用1start 启动当前线程 xff1b 调用当前线程的run 2run 通常需要重写Thread类中的此方法 xff0c 将创建的线程要执行的操作生命在此
  • 线程的同步机制

    方式一 xff1a 同步代码块 span class token keyword synchronized span span class token punctuation span 同步监视器 span class token punc
  • Java常用类总结

    一 字符串相关的类 String类及其常用方法 1 String声明为final的 xff0c 不可被继承 2 String实现了Serializable接口 xff1a 表示字符串是支持序列化的 xff1b 实现了Comparable接口
  • java获取两个字符串中最大相同字串

    span class token keyword import span span class token keyword static span java span class token punctuation span lang sp
  • jdk提供的4种注解

    元注解 xff1a 对现有的注解进行解释说明的注解 Retention xff1a 指定所修饰的Annotation的生命周期 xff1a SOURCE CLASS xff08 默认行为 xff09 RUNTIME xff0c 只有声明为R
  • Java中List接口常用方法

    List除了从Collection集合继承的方法外 xff0c List集合里添加了一些根据索引来操作集合元素的方法 xff1a 序号返回值函数作用1voidadd int index Object ele 在index位置插入ele元素2
  • 对Java中Class类的理解并获取Class实例

    关于java lang Class类的理解 类的加载过程 xff1a 程序经过javac exe命令以后 xff0c 会生成一个或多个字节码文件 class结尾 接着我们使用java exe命令对某个字节码文件进行解释运行 相当于将某个字节
  • 类加载器ClassLoader及应用

    类加载器ClassLoader span class token keyword public span span class token keyword class span span class token class name Cla
  • 创建运行时类的对象、调用运行时类的指定结构以及获取运行时类的完整结构

    创建两个类 一个注解 一个接口 用来准备测试 span class token keyword public span span class token keyword class span span class token class n
  • Lambda表达式基本使用的六种情况

    举例 xff1a o1 o2 gt Integer compare o1 o2 格式 xff1a lambda操作符 或 箭头操作符 左边 xff1a lambda形参列表 xff08 其实就是接口中的抽象方法的形参列表 xff09 右边
  • DBeaver登录Mysql所犯的低级错误

    1 简介 DBeaver是免费和开源 xff08 GPL xff09 为开发人员和数据库管理员通用数据库工具 2 安装DBeaver 3 DBeave连接MySQL 3 1 在DBeaver界面的左上角 xff0c 找到加号 xff0c 选
  • sql基础

    DB xff1a 数据库 database xff1a 存储数据的 仓库 它保存了一系列有组织的数据 DBMS xff1a 数据库管理系统 Database Management System 数据库是通过DBMS创建和操作的容器 SQL
  • SQL之DQL语言

    1 基础查询 语法 xff1a select 查询列表 from 表名 其中 xff1a 表中的字段 常量值 表达式 函数 查询字段 xff1a select 字段 多个字段中间逗号隔开 from 表名 查询常量值 xff1a select
  • Ubuntu中安装.deb格式的软件包

    使用dpkg命令进行安装 dpkg命令常用格式如下 xff1a sudo dpkg I iptux deb 查看iptux deb软件包的详细信息 xff0c 包括软件名称 版本以及大小等 xff08 其中 I等价于 info xff09
  • SQL之DDL(数据定义语言)

    1 库的管理 创建库 create database if not exists 库名 更改库的字符集 alter database 库名 character set gbk utf 8 删除库 drop database if exist

随机推荐