Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C fork()为每个进程打印列标题_C_Fork_Printf - Fatal编程技术网

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

C fork()为每个进程打印列标题,c,fork,printf,C,Fork,Printf,我正在编写一个简单的C程序,使用fork创建进程的二叉树。我能够得到进程、其父进程及其两个子进程的所有需要的输出。不幸的是,每个分叉进程都希望打印出列标题。如何确保头的printf只执行一次 # include <stdio.h> # include <stdlib.h> # include <sys/types.h> # include <unistd.h> # include <sys/wait.h> int main(int a

我正在编写一个简单的C程序,使用fork创建进程的二叉树。我能够得到进程、其父进程及其两个子进程的所有需要的输出。不幸的是,每个分叉进程都希望打印出列标题。如何确保头的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

我尝试了一些想法,包括那些在横幅部分下被注释掉的想法,但似乎没有任何效果,大多数修复使问题变得更糟

这里有一些东西可以试试,尽管我对这些东西有点生疏了。在打印横幅的行中:

printfLevel\tProcs\tpart\tChild1\tChild2\nNo。\tID\tID\tID\tID


可能是\n之后的所有内容都保留在输出缓冲区中,因此在分叉每个子项时它仍在那里。请尝试在该printf的末尾添加另一个\n,并从循环中printf的开头删除该\n。

这里有一些东西可以尝试,尽管我对这些东西有点生疏。在打印横幅的行中:

printfLevel\tProcs\tpart\tChild1\tChild2\nNo。\tID\tID\tID\tID

可能是\n之后的所有内容都保留在输出缓冲区中,因此在分叉每个子项时它仍在那里。请尝试在该printf的末尾添加另一个\n,并从循环中printf的开头删除该\n。

替换:

printf("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("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("\n");
替换:

printf("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("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("\n");
首先,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,或者调用fflushstdout;在for循环之前。

首先,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,或者调用fflushstdout;在for循环之前。

在此处阅读2.5.1:

请注意,在fork之后,两个句柄存在于一个句柄之前的位置。应用程序应确保,如果两个句柄都可以访问,则它们都处于另一个可以首先成为活动句柄的状态。应用程序应准备一个叉子,就像它是一个主动手柄的变化一样。如果其中一个进程执行的唯一操作是exec函数或_exitnot exit,则该进程中永远不会访问句柄

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

阅读2.5.1:

请注意,在fork之后,两个句柄存在于一个句柄之前的位置。应用程序应确保,如果两个句柄都可以访问,则它们都处于另一个可以首先成为活动句柄的状态。应用程序应准备一个叉子,就像它是一个主动手柄的变化一样。如果其中一个进程执行的唯一操作是exec函数或_exitnot exit,则该进程中永远不会访问句柄


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

我想我可以解释您看到的奇怪打印。您的sleep2和printf\n可能是fflush0s。添加fflushs会吗
tdout;在printf之后修复了什么?可能是stdio缓冲区被复制到子进程中,并且只在那里打印。是的!添加fflush确实解决了多重打印问题。我还删除了底部的\n打印,以避免多余的空行。另外,正如下面提到的,我必须在for循环中的processprint行之后放一个fflush。我想我可以解释你看到的奇怪的打印。您的sleep2和printf\n可能是fflush0s。添加fflushstdout;在printf之后修复了什么?可能是stdio缓冲区被复制到子进程中,并且只在那里打印。是的!添加fflush确实解决了多重打印问题。我还删除了底部的\n打印,以避免多余的空行。另外,正如下面提到的,我必须在for循环中的进程打印行之后放置一个fflush。我还必须在横幅打印声明之后添加一个。感谢您提供有关printf和换行符刷新的提示…这就解决了问题。这将创建一个不平衡的二叉树,因为只有第一次调用fork的父进程会由于短路而第二次fork。这可能是你的意图,也可能不是。@SiegeX:你说得对。使用|而不是| |应该可以解决这个问题。您完全正确地认识到在for循环之前需要使用fflush。我还必须在横幅打印声明之后添加一个。感谢您提供有关printf和换行符刷新的提示…这就解决了问题。这将创建一个不平衡的二叉树,因为只有第一次调用fork的父进程会由于短路而第二次fork。这可能是你的意图,也可能不是。@SiegeX:你说得对。用|代替| |应该可以解决这个问题。我认为这是正确的想法。上面的答案提到printf会刷新\n,所以您似乎是正确的。@John Smith yes@不过,DarkDust肯定比我有一个更彻底的答案。我认为这是正确的想法。上面的答案提到printf会刷新\n,所以您似乎是正确的。@John Smith yes@不过,DarkDust的回答肯定比我更透彻。