该程序在随机时间后将其管道连接到" head -n 1
"后生成SIGPIPE
。我知道因为我们在第一行之后输入更多"head -n 1
",我们希望它生成SIGPIPE
,但它会在退出之前变成一个随机数(通常> 20 和 <200(。知道为什么吗?
#include <stdio.h>
#include <stdlib.h>
main()
{
int i;
char *s = "ABCDEFGHIJKLMNOPQRSTUVWXYZn";
i = 0;
while (1) {
fputs(s, stdout);
fflush(stdout);
fprintf(stderr, "Iteration %d donen", i);
i++;
}
}
这不是家庭作业,只是我教授笔记中我不明白的东西。
这是日程安排的变幻莫测。
你的生产者——我们称之为alphabeta
——能够在head
能够读取和退出(从而破坏管道(之前运行一段时间。
当然,"一定时间"是可变的。
有时alphabeta
运行 20 次,head
才能读取 stdin 并退出。 有时200次。 在我的系统上,有时 300 次、1000 次或 2000 次。 事实上,从理论上讲,它可以达到连接生产者和消费者的管道的容量。
为了演示,让我们引入一些延迟,以便我们可以合理地确定head
在产生单行输出之前alphabeta
卡在 read(( 中:
so$ { sleep 5; ./alphabeta; } | head -n 1
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Iteration 0 done
(注意:不能保证alphabeta
在上面只迭代一次。 但是,在卸载的系统上,情况或多或少总是如此:head
将准备就绪,并且其读取/退出将或多或少立即发生。
相反,请观察当我们人为地延迟head
时会发生什么:
so$ ./alphabeta | { sleep 2; head -n 1; }
Iteration 0 done
...
Iteration 2415 done # <--- My system *pauses* here as pipe capacity is reached ...
Iteration 2416 done # <--- ... then it resumes as head completes its first read()
...
Iteration 2717 done # <--- pipe capacity reached again; head didn't drain the pipe
ABCDEFGHIJKLMNOPQRSTUVWXYZ
顺便说一句,@R..在他的评论中非常正确,SIGPIPE是同步的。 在您的情况下,第一次 fflush 诱导的对断开管道的写入(在head
退出后(将同步生成信号。 这是记录在案的行为。
我认为这仅仅是因为信号是异步的。
更新:正如其他人指出的那样,他们(更准确地说是许多,包括SIGPIPE(不是。这是一个不假思索的答案:)
接字写入是缓冲和异步的,因此在后续读取或写入之前,您通常不会收到特定写入引起的错误(。
head
命令使用 stdio 读取 stdin,因此第一个 getc 在缓冲区已满或 EOF 之前不会返回,以先发生者为准。