fork()导致为每个进程打印列标题

时间:2011-02-22 19:45:14

标签: c fork printf

我正在使用fork()编写一个简单的C程序来创建进程的二叉树。我能够得到我需要的所有输出(进程的pid,它的父进程和它的两个子进程)。不幸的是,每个分叉进程都想打印出列标题。如何确保标题的printf只执行一次?

# include <stdio.h>
# include <stdlib.h>
# include <sys/types.h>
# include <unistd.h>
# include <sys/wait.h>

int main(int argc, char *argv[]){

//Declarations
int i;
int child_1_pid, child_2_pid;
int num_levels = atoi(argv[1]);

//Output banners
//execlp("/bin/echo", "echo", "Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID", (char *) NULL);
//if(getpid() > 0)
printf("Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID");

//Creates binary tree of processes
for(i = 0; i < num_levels; i++){
    if((child_1_pid = fork()) && (child_2_pid = fork())){
        printf("\n%d\t%d\t%d\t%d\t%d", i, getpid(), getppid(), child_1_pid, child_2_pid);
        sleep(2); //prevents parent from terminating before child can get ppid (parent's pid)
        break; //why?       
    }   
}//end for

printf("\n"); //EXPLAIN ME!!
exit(0);
}//end main

还有一些代码(确实是错误检查),但我真正的问题是输出横幅部分下的printf执行多次,给出这样的输出(但正确对齐):

Level Procs   Parent  Child1  Child2
No.   ID  ID  ID  ID
No.   ID  ID  ID  ID
No.   ID  ID  ID  ID
No.   ID  ID  ID  ID
No.   ID  ID  ID  ID
No.   ID  ID  ID  ID
No.   ID  ID  ID  ID
0 30796   24743   30797   30798
1 30797   30796   30799   30800
1 30798   30796   30801   30802

我尝试了一些想法(包括那些在横幅部分注释掉的内容),但似乎没有任何效果,大多数“修复”使问题更严重!

4 个答案:

答案 0 :(得分:3)

首先,for循环中的if表现不像你想要的那样。请记住,在fork之后,它返回父进程中的子PID和子进程中的0。因此,在循环内部,第一个fork为父级中的child_1_pid分配一个值,并继续执行第二个子句。子进程不会进入if,而是继续进行下一个for循环迭代。第二个条款也是如此。所以只有主进程才能进入if的主体,但没有子进程。我想知道为什么输出表明不然。

为了得到你的“二叉树”,你应该真的有这个:

// COMPLETELY UNTESTED
for(i = 0; i < num_levels; i++){
    if (!(child_1_pid = fork()) || !(child_2_pid = fork())) {
        printf("\n%d\t%d\t%d\t%d\t%d", i, getpid(), getppid(), child_1_pid, child_2_pid);
        // A child process, go on to next iteration.
        continue;
    }

    // A parent process. Wait for children, then stop.
    if (child_1_pid) wait();
    if (child_2_pid) wait();
    break;
}

横幅的奇怪输出与潮流有关。通常情况下,fprintf仅在新行(\n),IIRC上刷新。因此,在尚未刷新的fork之后仍然存在缓冲区中的内容,并且每个子节点都运行printf("\n");,从而刷新缓冲区内容。

解决方案是在第一个printf的末尾添加“\ n”,或者在fflush(stdout);循环之前调用for

答案 1 :(得分:2)

这里有一些尝试,虽然我对这些东西有点生疏。在您打印横幅的行中:

  

的printf( “等级\ tProcs \ tParent \ tChild1 \ tChild2 \ n无\的tID \的tID \的tID \的TID。”);

可能是\n之后的所有内容都留在了输出缓冲区中,所以当每个孩子分叉时它仍然存在。尝试在\n的末尾添加另一个printf,并从循环内\n的开头删除printf

答案 2 :(得分:1)

替换:

printf("Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID");

使用:

puts("Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID");

替换:

printf("\n%d\t%d\t%d\t%d\t%d", i, getpid(), getppid(), child_1_pid, child_2_pid);

使用:

printf("%d\t%d\t%d\t%d\t%d\n", i, getpid(), getppid(), child_1_pid, child_2_pid);

卸下:

printf("\n");

答案 3 :(得分:0)

在这里阅读2.5.1:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html

  

请注意,在fork()之后,存在两个句柄,其中之前存在一个句柄。应用程序应确保,如果可以访问这两个句柄,它们都处于另一个可以成为活动句柄的状态。应用程序应准备fork(),就像它是活动句柄的更改一样。 (如果其中一个进程执行的唯一操作是exec函数之一或_exit()(而不是exit()),则永远不会在该进程中访问句柄。)

这意味着,在调用fork之前,您应该在fflush之后的两个进程中的任何流上调用fork