【发布时间】:2014-11-27 22:09:39
【问题描述】:
考虑一个程序,它创建一个无限循环打印的子进程,并在一秒钟后将其杀死:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
int main(void) {
pid_t pid = fork();
if (pid == 0) {
while (1)
puts("I'm still alive");
} else {
sleep(1);
puts("Dispatching...");
kill(pid, SIGTERM);
puts("Dispatched!");
}
return 0;
}
正如我所料,输出是:
I'm still alive
I'm still alive
...
Dispatching...
I'm still alive
I'm still alive
...
Dispatched!
这是有道理的,因为子进程可能不会在父亲发送信号后立即终止。
但是,一旦我通过管道运行程序,或将输出重定向到另一个文件,例如
$ ./prog | tail -n 20
$ ./prog > out.txt
输出变成:
I'm still alive
I'm still alive
...
Dispatching...
Dispatched!
也就是说,似乎是父进程杀死子进程后没有输出。
造成这种差异的原因是什么?
【问题讨论】:
-
我认为下一个是有道理的:stackoverflow.com/questions/9553628/piping-and-redirection?rq=1,虽然第一个是发送到输出缓冲区,但在 kill 之后缓冲区仍然有一些数据,而管道正在阻塞并直接通过通道,所以,一旦被杀死,就没有什么可看的了。这有意义吗?
-
我认为情况正好相反:如果
stdout是一个 tty 刷新发生在每个换行符上,而重定向输出分流器的刷新频率较低,尤其是。在只打印两行的主进程的情况下,刷新只会在它终止后发生,所以所有子进程的输出都在此之前写入 -
@HartmutHolzgraefe 这实际上是有道理的 - 因为
stdout在绑定到文件或管道时没有行缓冲,所以只有在它终止后才刷新父亲的输出,而孩子的输出是在kill()之后立即刷新。
标签: c unix process io-redirection piping