简体   繁体   English

通过一个简单的例子来理解C的fork()

[英]Understanding C's fork() through a simple example

#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);
}

I'm having trouble understanding why the possible outputs would be 0102 or 0012 or 0201 or 0021. 我无法理解为什么可能的输出是0102或0012或0201或0021。

Here is what I (think) it should be producing. 这是我认为它应该产生的东西。 It hits the first printf statement and no matter what child or parent gets executed first, num hasn't been modified so 0 first. 它命中第一个printf语句,无论先执行什么子项或父项,num都没有被修改为0。 THEN next is either 1 or 2, then the next process executes so starts with 0 again (copied from the parent) and then either a 1 or 2 again. 那么接下来是1或2,然后执行下一个过程,所以再次从0开始(从父项复制),然后再次从1或2开始。 So the possible outputs should be: 所以可能的输出应该是:

0101 or 0102 or 0201 or 0202 0101或0102或0201或0202

In both the parent and the child, num is 0 for the first printf . 在父级和子级中,第一个printf num为0。 In both the parent and the child, 0 is printed followed by the other value. 在父和子中,打印0,然后打印另一个值。 In the parent process, the other value is 2. In the child process, the other value is 1. 在父进程中,另一个值为2.在子进程中,另一个值为1。

However, the important thing to note is that although each process has an enforced order that zero has to be printed before the other number, there is no restriction on the printing of the two processes relative to each other. 但是,需要注意的重要一点是,虽然每个进程都有强制订单,零必须在另一个数字之前打印,但两个进程相对于彼此的打印没有限制。

Here's a real-life analogy: Suppose my coworker and each I leave work at the same time, stop at the grocery store, and then arrive home. 这是一个真实的比喻:假设我的同事和我每个人同时离开工作,停在杂货店,然后到家。 We know I was at the store before I was at my home, and we know he was at the grocery store before he was at his home. 我知道我在家之前就在商店,我们知道他在家之前就在杂货店。 But we don't know who was at the grocery store first, or who was at home first. 但我们不知道谁先在杂货店,或者谁先在家。 We could each arrive at the grocery store around the same time and then each arrive home around the same time, or maybe he's delayed and I get the grocery store and home before he even gets to the store. 我们每个人都可以在同一时间到达杂货店,然后每个人大约在同一时间到家,或者他可能会被推迟,我甚至在他去商店之前就去了杂货店和家。

Something that won't happen is the printing of 1 or 2 more than once. 不会发生的事情是不止一次打印1或2。 Although after fork returns we have two processes running conceptually at once, and the timing of their events relative to each other is unspecified, the order of events in each process is well defined. 虽然在fork返回之后我们有两个进程在概念上同时运行,并且它们的事件相对于彼此的时间是未指定的,但是每个进程中的事件顺序都是明确定义的。 Each process will set num to either 1 or 2 before printing it again, and because fork is defined to return 0 in the child and the child's pid in the parent, they will each set it to different values. 每个进程在再次打印之前将num设置为1或2,并且因为fork被定义为在子节点中返回0而子节点中的子节点pid,它们将各自设置为不同的值。

There is, actually, another reasonable output: 00 . 实际上,还有另一个合理的输出: 00 If fork is unable to create a new process, it returns -1. 如果fork无法创建新进程,则返回-1。 In this case program will print 0 , the if and else if s will fail because -1 is neither 0 nor greater than 0, num is not changed, and the program prints 0 again. 在这种情况下,程序将打印0ifelse if将失败,因为-1既不是0也不是大于0,num没有改变,程序再次打印0

If you want to learn a lot about the definition of the ordering of effects in C programs, the key words to search for are "sequence points". 如果你想学习很多关于C程序中效果排序的定义,搜索的关键词是“序列点”。 In this program it's fairly straightforward (aside from the fact that we have two copies running at once), but it can sometimes be less obvious. 在这个程序中它是相当简单的(除了我们一次运行两个副本的事实),但它有时可能不那么明显。

This is not the problem with fork() . 这不是fork()的问题。 It is the printf() since printf() is buffered. 它是printf()因为printf()是缓冲的。 Normally the buffer is flushed when it encounters a newline character at the end, '\\n'. 通常,缓冲区在最后遇到换行符时会被刷新,'\\ n'。 However since you have omitted this, the contents of the buffer stays and is not flushed. 但是,由于您省略了这一点,缓冲区的内容会保留并且不会被刷新。 In the end, both processes (the original and the child) will have the output buffer with 0 or 1 in it. 最后,两个进程(原始进程和子进程)将具有0或1的输出缓冲区。 When it eventually gets flushed, you'll see this in both processes. 当它最终被刷新时,你会在两个进程中看到这一点。

add fflush(stdout); 添加fflush(stdout); after printf() and try. printf()之后尝试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM