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大小 文件名
相关推荐
ONE_PUNCH_Ge20 小时前
Go 语言泛型
开发语言·后端·golang
良许Linux20 小时前
DSP的选型和应用
后端·stm32·单片机·程序员·嵌入式
咕噜咕噜啦啦20 小时前
ROS入门
linux·vscode·python
不光头强20 小时前
spring boot项目欢迎页设置方式
java·spring boot·后端
Yana.nice21 小时前
证书格式的适用场景与核心对比
java·linux
怪兽毕设21 小时前
基于SpringBoot的选课调查系统
java·vue.js·spring boot·后端·node.js·选课调查系统
爱装代码的小瓶子21 小时前
【C++与Linux基础】文件篇(8)磁盘文件系统:从块、分区到inode与ext2
linux·开发语言·c++
PPPPPaPeR.21 小时前
程序地址空间
linux·算法
学IT的周星星21 小时前
Spring Boot Web 开发实战:第二天,从零搭个“会卖萌”的小项目
spring boot·后端·tomcat
郑州光合科技余经理21 小时前
可独立部署的Java同城O2O系统架构:技术落地
java·开发语言·前端·后端·小程序·系统架构·uni-app