为什么这个C程序比预期更晚生成SIGPIPE?

时间:2013-05-05 00:30:49

标签: c sigpipe

此程序在随机时间之后将其汇总到“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++;
  }
}

这不是家庭作业,只是在我教授的笔记中,我不明白。

4 个答案:

答案 0 :(得分:8)

这是调度的变幻莫测。

您的制作人 - 我们称之为alphabeta - 能够在head能够读取和退出(因此破坏管道)之前运行一段时间。

当然,“一些时间”是可变的。

有时alphabetahead读取标准输入并退出之前运行20次。有时200次。在我的系统上,有时300或1000或2000次。实际上,它理论上可以循环到连接生产者和消费者的管道容量。

为了演示,让我们引入一些延迟,以便我们可以合理地确定headalphabeta产生单行输出之前卡在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之前不会返回,以先发生者为准。