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大小 文件名
相关推荐
程序视点2 分钟前
Redis集群机制及一个Redis架构演进实例
java·redis·后端
杰克崔4 分钟前
关于stac和clac的进一步细节及EFLAGS
linux·运维·服务器
鱼樱前端7 分钟前
Navicat17基础使用
java·后端
黑风风25 分钟前
深入理解Spring Boot Starter及如何自定义Starter
java·spring boot·后端
uhakadotcom37 分钟前
BM25 算法入门与实践
后端
鱼樱前端42 分钟前
Mac M1安装MySQL步骤
java·后端
hxung1 小时前
Linux 命令学习记录
linux·运维·学习
uhakadotcom1 小时前
Istio 服务网格:连接、保护和优化微服务的利器
后端·面试·github
yi个名字1 小时前
Linux进程基础知识
linux·运维·服务器
Asthenia04122 小时前
Spring事务分析:@Transactional用久了,是不是忘了编程式事务了?
后端