如果你使用管道将两个进程 - 父进程和子进程 - 连接起来,那么在fork之前需要创建管道。
fork使得两个进程都可以访问管道的两端口,这是不可取的。
读取端口应该在它注意到EOF条件时学会写入者已经完成。只有当所有写入端口关闭时才能发生这种情况。因此最好尽快关闭它的写入FD。
为了避免打开太多的FD(文件描述符),作者应该关闭其读取FD,并且不要达到可能存在的打开FD数量的限制。此外,如果仅剩的读取器死亡,则通过获得SIGPIPE或至少是EPIPE错误(取决于信号如何定义)来通知作者。如果有多个读者,作者无法检测到"真正的读者"走了,它继续写入并被阻塞,希望“未使用”的读取器将读取一些东西。
所以这里详细说明了发生了什么:
pipe()
并获得2个文件描述符:我们称它为rd
和wr
。fork()
。现在两个进程都有一个rd
和一个wr
。假设子进程是读取者。
那么:
fork
创建子进程,关闭其写入端口,并尝试从管道中读取。exec
运行不同的程序:
exec
失败,例如因为程序不存在,子进程将errno
写入管道,父进程读取它并知道出了什么问题,并可以告诉用户。exec
成功,则在不写入任何内容的情况下关闭管道。父进程中的read
函数返回0,表示管道已关闭,并且知道程序已成功启动。如果父进程在尝试从管道中读取之前没有关闭其写入端口,则此过程将无法正常工作,因为当exec
成功时,read
函数将永远不会返回。
read()
将阻塞等待数据,因为内核知道该管道仍然至少有一个写入描述符处于打开状态。这个描述符由读取进程自身保持打开状态是无关紧要的。理论上,该进程仍然可以向管道中写入数据,即使它正在尝试读取并被阻塞。read()
可能会被信号处理程序中断,并向管道写入数据。SIGPIPE
信号。默认情况下,此信号会杀死进程。进程可以安排捕获或忽略此信号,在这种情况下,管道上的 write()
将失败,并显示错误 EPIPE
(断开的管道)。接收到 SIGPIPE
信号或获取 EPIPE
错误是有关管道状态的有用指示,这就是为什么应该关闭未使用的管道读取描述符的原因。