此程序在随机时间之后将其汇总到“SIGPIPE
”后生成head -n 1
。我理解,因为我们在第一行之后向“head -n 1
”提供更多信息,我们希望它会生成SIGPIPE
,但它会使其成为一个随机数(通常> 20和在退出之前< 200)。知道为什么吗?
#include <stdio.h>
#include <stdlib.h>
main()
{
int i;
char *s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
i = 0;
while (1) {
fputs(s, stdout);
fflush(stdout);
fprintf(stderr, "Iteration %d done\n", i);
i++;
}
}
这不是家庭作业,只是在我教授的笔记中,我不明白。
答案 0 :(得分:8)
这是调度的变幻莫测。
您的制作人 - 我们称之为alphabeta
- 能够在head
能够读取和退出(因此破坏管道)之前运行一段时间。
当然,“一些时间”是可变的。
有时alphabeta
在head
读取标准输入并退出之前运行20次。有时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
退出后)将同步生成信号。这是documented behavior。
答案 1 :(得分:4)
我认为这只是因为信号是异步的。
更新:正如其他人所指出的那样(更确切地说是许多,包括SIGPIPE)不是。这是一个不切实际的答案:)
答案 2 :(得分:0)
套接字写入是缓冲和异步的,因此在下一次读取或写入之前,通常不会出现特定写入引起的错误。
答案 3 :(得分:0)
head
命令使用stdio读取stdin,因此第一个getc在缓冲区已满或EOF之前不会返回,以先发生者为准。