此代码的输出没有意义

时间:2014-01-27 18:57:08

标签: c fork

给出以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void){
    int i;
    printf("My PID: %d \n", getpid());

    for(i=0; i<3;i++){
        if (fork()==0){
            printf("Son PID: %d\n", getpid());
            return 0;
        }
    }
    while(wait(NULL)!=-1);
    printf("OK!\n");
    return 0;
}

我得到了以下输出:

My PID: 13695 
Son PID: 13696
My PID: 13695 
Son PID: 13697
My PID: 13695 
Son PID: 13698
My PID: 13695 
OK!

我不知道为什么'MY PID:13695'打印不止一次(开头)。 这是怎么回事?

编辑:它适用于我的系统但是当我在其他几个系统上运行时,我确实得到了如上所述的输出。 例如:http://www.compileonline.com/compile_c_online.php

这是我在测试中被问到的一个问题,我不确定答案是什么。

3 个答案:

答案 0 :(得分:2)

% cat > t.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void){
    int i;
    printf("My PID: %d \n", getpid());

    for(i=0; i<3;i++){
        if (fork()==0){
            printf("Son PID: %d\n", getpid());
            return 0;
        }
    }
    while(wait(NULL)!=-1);
    printf("OK!\n");
    return 0;
}
% gcc t.c
% ./a.out 
My PID: 23382 
Son PID: 23383
Son PID: 23384
Son PID: 23385
OK!

我唯一的猜测是某些环境可能不会从第一个printf刷新缓冲区,所以第一个字符串仍然在内存中,当孩子打印第二个消息然后退出时应该导致缓冲区刷新任何操作环境。

答案 1 :(得分:2)

一种可能性是在fork()调用之前未刷新输出缓冲区。 fork()基本上复制了程序的整个状态,包括输出缓冲区,因此每个子进程在其输出缓冲区中都有“My PID ...”字符串(注意该行上的PID不会改变) 。当缓冲区最终被刷新时,您将获得整个内容,即父进程放在那里的行。

要解决此问题(根据下面的Zack评论),在第一个fflush(0);printf()之间的某处添加fork(),以便输出缓冲区在被复制之前被清除,因为fork()来电。{/ p>

答案 2 :(得分:2)

部分(但不是全部)C库在第一次写入stdout时检测到它是否连接到终端(就像通过调用isatty一样) 。如果是,则将stdout设置为行缓冲而不是完全缓冲。在这样的系统上,当程序写入终端时(并且仅当它)写入终端时,该程序将产生预期的输出。据推测这是&#34;在线C编译器&#34;事情是使用其他形式的IPC来捕获程序的输出,因此不会触发这种特殊情况。如果您看到此程序产生预期输出,请尝试运行

$ ./a.out | cat

你几乎肯定会看到它像Shookie描述的那样。

要使程序在所有上下文中按预期运行,只需在fork之前立即拨打fflush

...
int
main(void)
{
    int i;
    printf("My PID: %d \n", getpid());

    for (i=0; i<3;i++) {
        fflush(0);
        if (fork() == 0) {
...

(在这个的情况下,你可以使用fflush(stdout)而不是fflush(0),而你可以放弃将它放在循环之前,但在一般情况下它需要在fork调用之前立即 ,它需要刷新所有打开的文件,而不仅仅是stdout。)