考虑一个程序,它在无限循环中创建子进程打印,并在一秒后终止它:
#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!
也就是说,在父亲杀死子进程之后,似乎没有来自子进程的输出.
造成这种差异的原因是什么?
最佳答案 puts使用
stdio,可以是
buffered.通常,当stdout连接到终端时,它是行缓冲的,这意味着每次打印换行时都会刷新缓冲区.因此,当您在不重定向其输出的情况下运行程序时,每次行都会在puts调用时打印.当程序的标准输出重定向到文件或管道时,stdout变为完全缓冲:输出数据在缓冲区中累积,仅在缓冲区已满时写出.程序在有时间填充缓冲区之前被杀死,因此您看不到任何输出.
您可以通过调用setvbuf(stdout,NULL,_IOLBF,BUFSIZ)来确认这是您正在观察的内容,以便在输出任何内容之前将stdout设置为行缓冲模式.然后,您应该看到相同数量的行,无论输出是转到终端,还是文件或管道.
也可以观察其他效果;在这种规模下,行为非常依赖于调度程序的微调.例如,终端渲染输出所需的时间,其他程序同时运行的程序,您运行程序的shell是否最近一直在进行CPU密集型或IO密集型操作可能很重要…