9
#include <stdio.h>
int num = 0;
int main(int argc, char*argv[]){
    int pid;
    pid = fork();
    printf("%d", num);  
    if(pid == 0){       /*child*/
        num = 1;
    }else if(pid > 0){  /*parent*/
        num = 2;
    }
    printf("%d", num);
}

我无法理解为什么可能的输出是 0102 或 0012 或 0201 或 0021。

这是我(认为)它应该产生的。它命中第一个 printf 语句,无论哪个子或父首先执行,num 都没有被修改,所以首先为 0。THEN next 是 1 或 2,然后执行下一个进程,因此再次从 0 开始(从父级复制),然后再次为 1 或 2。所以可能的输出应该是:

0101 或 0102 或 0201 或 0202

4

2 回答 2

10

在父级和子级中,第一个 num 为 0 printf。在父级和子级中,打印 0 后跟另一个值。在父进程中,另一个值为2。在子进程中,另一个值为1。

然而,需要注意的重要一点是,虽然每个进程都有一个强制顺序,即必须在另一个数字之前打印零,但两个进程的打印相对于彼此没有限制。

这是一个现实生活中的类比:假设我的同事和我每个人同时下班,在杂货店停下来,然后回到家。我们知道我在我在家之前就在商店,我们知道他在他在家之前就在杂货店。但我们不知道谁先到杂货店,或者谁先到家。我们可以每个人大约在同一时间到达杂货店,然后每个人大约在同一时间到家,或者他可能延误了,我在他到达商店之前就到了杂货店和家。

不会发生的情况是多次打印 1 或 2。尽管在fork返回之后,我们有两个进程在概念上同时运行,并且它们的事件相对于彼此的时间是未指定的,但每个进程中事件的顺序是明确定义的。每个进程num在再次打印之前将设置为 1 或 2,并且由于fork定义为在子进程中返回 0 并且在父进程中返回子进程的 pid,因此它们将各自将其设置为不同的值。

实际上,还有另一个合理的输出:00. 如果fork无法创建新进程,则返回-1。在这种情况下,程序将打印0if并且else ifs 将失败,因为 -1 既不是 0 也不是大于 0,num 没有改变,程序0再次打印。

如果想深入了解 C 程序中效果排序的定义,搜索的关键词是“序列点”。在这个程序中,它相当简单(除了我们同时运行两个副本),但有时它可能不太明显。

于 2013-03-07T04:11:27.657 回答
9

这不是问题fork()。它是printf()因为printf()被缓冲。通常,当缓冲区在末尾遇到换行符'\n'时会刷新缓冲区。但是,由于您省略了这一点,因此缓冲区的内容会保留并且不会被刷新。最后,两个进程(原始进程和子进程)都会有输出缓冲区,其中包含 0 或 1。当它最终被刷新时,您会在两个进程中看到这一点。

fflush(stdout);之后添加printf()并尝试。

于 2013-03-07T04:15:01.347 回答