SIGPIPE 到底在什么条件下发生?

SIGPIPE 到底在什么条件下发生?

假设我们有一个名为 的命名管道fifo,并且我们正在从两个不同的 shell 中读取和写入它。考虑这两个例子:

shell 1$ echo foo > fifo
<hangs>
shell 2$ cat fifo
foo
shell 1$ echo bar > fifo
<hangs>

shell 1$ cat > fifo
<typing> foo
<hangs>
shell 2$ cat fifo
foo
^C
shell 1$
<typing> bar
<exits>

我无法理解这些示例中发生的情况,特别是为什么在第一个示例中尝试将“bar”写入管道会导致阻塞调用,而在第二个示例中它会触发 SIGPIPE。

我确实理解,在第一种情况下,两个单独的进程写入管道,因此它被打开两次,而在第二种情况下,它仅被单个进程打开一次并写入两次,进程从管道中读取在此期间被杀。我不明白的是这如何影响 的行为write

手册pipe(7)页指出:

如果所有引用管道读取端的文件描述符都已关闭,则(2) 将导致为调用进程生成SIGPIPE信号。

这个条件对我来说听起来不太清楚。 A关闭文件描述符就不再是文件描述符了,对吧?怎么说“管道的读取端已关闭“ 与......不同 ”管道的读数端未打开“?

我希望我的问题足够清楚。顺便说一句,如果您能建议详细了解 Unix 管道与open、和操作相关的功能,我将不胜感激。closereadwrite

答案1

您的示例使用的是 afifo而不是 a pipe,因此受fifo(7)pipe(7)还告诉:

FIFO(先进先出的缩写)在文件系统中具有名称(使用 mkfifo(3) 创建),并使用 open(2) 打开。任何进程都可以打开 FIFO,前提是文件权限允许。使用O_RDONLY标志打开读端;使用 O_WRONLY 标志打开写入端。 有关详细信息,请参阅 fifo(7)。 注意:尽管 FIFO 在文件系统中具有路径名,但 FIFO 上的 I/O 不涉及底层设备(如果有的话)上的操作。

管道和 FIFO 上的 I/O
管道和 FIFO 之间的唯一区别在于它们创建和打开的方式。一旦完成这些任务,管道和 FIFO 上的 I/O 就具有完全相同的语义。

所以现在从fifo(7):

内核为至少一个进程打开的每个 FIFO 特殊文件维护一个管道对象。必须先打开 FIFO 两端(读和写),然后才能传递数据。通常,打开 FIFO 会阻塞,直到另一端也打开为止。

因此,在两端(这里意味着至少有一个读取器和一个写入器)打开之前,按照 写入块fifo(7)。在两端都打开,然后读取端关闭后,写入会根据 生成 SIGPIPE pipe(7)

有关管道使用(不是 fifo)的示例,请参见的示例部分pipe(2):涉及到pipe()(没有open(),因为pipe()实际上创建了打开的管道对)、close()、read()、write()和fork()(使用管道时几乎总是有一个fork()) )。

如果您不希望在写入 fifo 时死掉,从您自己的 C 代码处理 SIGPIPE 的最简单方法是通过在每次 write() 之后signal(SIGPIPE, SIG_IGN);检查 errno 来调用和处理它。EPIPE

答案2

写入没有读取过程的管道或 FIFO 将被视为错误条件;它会生成 SIGPIPE 信号,如果该信号被处理或阻止,则会失败并显示错误代码 EPIPE。

相关内容