匿名管道

发布时间 2023-10-29 11:56:41作者: cerwang

匿名管道常常用来实现父子进程的通信。通过pipe函数创建两个文件描述符,分别指向管道的两端。

从内核对于共享文件的实现来理解管道

  • 描述符表。每个进程都有它独立的描述符表,它的表项是由进程打开的文件描述符来索引的。每个打开的描述符表项指向文件表中的一个表项。
  • 文件表。所有的进程共享这张表。每个文件表的表项组成(针对我们的目的)包括当前的文件位置、引用计数(即当前指向该表项的描述符表项数), 以及一个指向 v-node 表中对应表项的指针。关闭一个描述符会减少相应的文件表表项中的引用计数。直到它的引用计数为零,内核删除这个文件表表项。
  • v-node表。所有的进程共享这张表。每个表项包含 stat 结构中的大多数信息,包括 st_mode 和 st_size 成员

多个文件描述符可以通过不同的文件表表项引用同一个文件,比如对同一个文件open了多次就会产生以下结果
imag

父子进程对于文件共享的实现就是fork后,父子进程具有相同的文件描述符表,因而共享相同的文件位置。只有父子进程都关闭了相应文件描述符,内核才会删除对应的文件表表项。
image

因此管道用于父子进程通信的情形就像下面这张图(管道由父进程创建)
image

单个管道不用于双向通信,一个管道只用于单向的字节流原因:
如果一个进程可以对管道进行读写,可能会导致写入的字节又被自己读出,这显然是违背意图的。

在使用管道时,写进程关闭读端,读进程关闭写端的原因:

  • 减少管道占用资源
  • 如果读进程没有关闭写的文件描述符,那么即使写进程已经关闭了写入的描述符,由于仍有一个写入的描述符开着,读进程执行read的时候会保持阻塞。如果写进程没有关闭读的文件描述符,那么即使读进程已经已经关闭了读的描述符,写进程仍然能够往管道里写入,导致写满管道然后阻塞。正常情况,也就是当没有读的文件描述符存在时,写入管道操作会让当前进程收到SIGPIPE信号。

那该怎么实现双向通信?
使用两个匿名管道,分别用于单向的字节流。