代码改变世界

Linux -- 进程间通信之管道

2019-11-26 15:32  陈心朔  阅读(333)  评论(0编辑  收藏  举报

管道是 Linux 里的一种文件类型,同时也是 Linux 系统下进程间通信的一种方式

 

创建一个管道文件有两种方式:

  1. Shell 下命令 mkfifo + filename,即创建一个有名管道
  2. C 语言里调用 pipe() 函数,创建一个无名管道

有名管道 / 无名管道

区别:

  1. 有名管道在程序外部使用 mkfifo 命令生成,无名管道在程序内部调用 pipe() 函数创建;
  2. 顾名思义,有名管道有文件名,无名管道没有文件名;
  3. 有名管道生成后直到删除都存在,无名管道在程序退出时则生命周期结束;
  4. 有名管道可以在任意两个进程间传输数据,无名管道只能在父子进程间传输数据;

注意:有名/无名管道都是半双工,即只能从一端向另一端发送数据,输入端与输出端在打开管道时是固定的

管道文件的特性

  1. 打开管道必须有两端(两个进程)同时打开一个管道,分别为读(r)和写(w);读取端负责从管道中读取数据,写入端负责向管道中输入数据;
  2. 当读端关闭,写端会收到信号,终止程序;当写端关闭,读端不再进入阻塞;
  3. 管道文件的大小始终为 0,打开管道文件时,在内存中为其分配空间,管道关闭后数据消失;Linux 默认 PIPE_SIZE(一个管道最大存储大小)为 64k,PIPE_BUF(管道缓冲区)为 4k;当对管道进行 write 操作时,若此时有多个进程同时写入一个管道,且写入的字节大小超过 PIPE_BUF,则写操作的数据有可能相互穿插

管道文件的内存空间有两个指针 head / tail ,head 指针随读取数据向后移动,tail 指针随写入数据向后移动,当指针到文件尾时,会造成读阻塞 (读取结束)/ 写阻塞(空间已满)
 
注意
当我们调用 pipe() 创建无名管道后 fork() 以实现父子进程间通信,此时 pipe() 生成的两个 r/w 描述符引用都会加一,在父子进程中同时存在 r/w 两个描述符,此时应当在父子进程中分别 close 不用的描述符,使 r/w 端只存在一个引用,这样父子进程间通信时可以正常读写响应