Linux进程间通信(1)-管道、内存映射

无名管道

unix最古老的管道:

  • 半双工(只能进行一个方向的读写)
  • 在内存缓存区中(所以不属于文件系统),大小由系统决定,使用ulimit -a查看
  • 数据先入先出且按字节(所以没有格式)传出,读取后就抛弃
  • 只能在具有公共祖先(3代以内)的进程中使用

创建

#include <unistd.h>

int pipe(int filefd[2]);

  • filefd也是用来接受返回的,接受两个文件描述符
  • 创建的管道使用文件描述符进行操作
  • 管道pipefd[0]用于读,pipefdp[1]用于写
  • 失败返回-1

操作

与文件操作一样,都是调用write、read,只是由于只能先进先出,所以不能使用lseek()等函数

读写控制

阻塞只与管道有关,而不是与write和read函数相关,管道的读写都有计数器,close相应管道后就会对应-1

读管道(阻塞):

  • 管道中有数据,read返回实际读取的字节数
  • 无数据
    • 写端计数为0,则直接返回0,且不会修改buffer;
    • 仍然有写端,则阻塞

写管道:

  • 读端为0,进程异常终止
  • 仍有读端
    • 管道已满,write阻塞
    • 管道未满,write将数据写入,并返回实际写入的字节数

读管道(非阻塞)

  • 写端没有关闭,管道没有数据,直接返回-1

  • 设置方法:

    c 复制代码
    int flags = fcntl(fd[0],F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(fd[0],F_SETFL,flags);

有名管道FIFO

  • 就是一个特殊文件,内容放置于内存,程序能及时写入读取
  • 对通信进程不做要求

创建

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(const char *filename, mode_t mode);

  • mode就是设置权限,和chmod一样,如644
  • shell中创建:mkfifo 文件名

操作

  1. 首先打开该管道(文件)获得文件描述符
  2. 后续与文件操作一样,只是不能使用lseek

读写控制

  • 以只读/只写形式打开文件,会阻塞等待另一个进程只写/只读形式打开
  • 和无名管道一致

存储映射(内存映射)

  1. 本质上是将文件指定区域映射到程序的内存中,程序对此部分内存的操作就是对文件的操作,减少系统调用write、read,进而减少了模态切换而造成的开销
  2. 如果两个进程同时对一个文件同块区域进行了存储映射,那这两个进程就实现了通信
  3. 每次都需要一个文件会很麻烦,系统提供了匿名存储映射,不需要提供文件,但是只能用于父子进程,因为此时两者都具有指向该内存空间的指针

创建

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

  • addr 指定内存指针,一般设置NULL让系统自行分配
  • length 设置内存、文件映射区域大小,注意文件分配的内存要>=length
  • prot 设置该区域的访问权限PROT_WRITE|PROT_READ
  • flags 设置该区域数据被修改后程序的行为,MAP_SHARED|MAP_ANONYMOUS
  • fd 文件描述符,匿名映射可以不设置
  • offset 设置文件从哪开始映射到内存中
  • 如果成功则返回指向该区域的内存指针,否则返回MAP_FAILED

操作

  1. 首先打开文件,获得文件描述符(匿名不需要)
  2. 调用
c 复制代码
void  *addr = mmap(NULL,512,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
  1. 关闭文件(匿名不需要)
  2. 写存储映射区
  3. 断开存储映射munmap(addr,1024)

补充

  1. 何时写入磁盘?
  • flag为MAP_SHARED,由系统决定何时写回
    • munmap调用
    • 程序退出
    • 系统内存不足
  • 强制写回:
    int msync(void addr[.length], size_t length, int flags); 其中flags为NS_ASYNC
  1. 能否感知文件内容变化
  • flag为MAP_SHARED时,能直接感知到其他进程对文件内容的更新(注意其他进程得写回磁盘);
  1. 写入的是什么?
  • 将映射内存的全部内容直接覆盖原本文件中的指定区域
  1. 如果文件分配的磁盘大小<length会怎么样
  • 出现Bus error (core dumped)
  • 解决方法:创建文件并分配 length 字节的空间
    truncate -s length大小 文件名
相关推荐
命中的缘分30 分钟前
SpringCloud原理和机制
后端·spring·spring cloud
ErizJ30 分钟前
Golang|分布式索引架构
开发语言·分布式·后端·架构·golang
.生产的驴31 分钟前
SpringBoot 接口国际化i18n 多语言返回 中英文切换 全球化 语言切换
java·开发语言·spring boot·后端·前端框架
Howard_Stark35 分钟前
Spring的BeanFactory和FactoryBean的区别
java·后端·spring
-曾牛44 分钟前
Spring Boot中@RequestParam、@RequestBody、@PathVariable的区别与使用
java·spring boot·后端·intellij-idea·注解·spring boot 注解·混淆用法
奶油话梅糖1 小时前
LS-Linux-004 误删 Python 和 yum、dnf 后的恢复步骤
linux
极客智谷1 小时前
Spring AI应用系列——基于Alibaba DashScope的聊天记忆功能实现
人工智能·后端
极客智谷1 小时前
Spring AI应用系列——基于Alibaba DashScope实现功能调用的聊天应用
人工智能·后端
RJiazhen1 小时前
5分钟让你的服务接入AI——用 API Auto MCP Server 实现大模型与后端系统的无缝对话
后端·开源·mcp
前端付豪1 小时前
2、ArkTS 是什么?鸿蒙最强开发语言语法全讲解(附实操案例)
前端·后端·harmonyos