为什么这个C程序生成SIGPIPE的时间晚于预期



该程序在随机时间后将其管道连接到" 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 之前不会返回,以先发生者为准。

最新更新