2011-10-03 146 views
4

我很难理解fork()命令在不同场景下执行的操作。下面是我的书,一些示例代码:与fork相混淆()

int main() { 
    int a = 12; 
    int b = 9; 
    int fid = fork(); 

    if (fid == 0) { 
     a++; 
    } 
    else { 
     wait(NULL); 
     b = b - 5; 
    } 

    printf("program exit. a = %d, b = %d\n", a, b); 
    return 0; 
} 

有人能走我通过什么叉()命令在这种情况下,这样做也许会给一些例子来澄清?

+0

请注意,处理'fork()'时没有多线程(标记已移除)。您正在处理多个进程(多处理),而不是单个进程内的多个线程(多线程)。 –

+0

fork()也可以返回-1,也许你可以用switch(fid){...}来处理。 –

+0

@JonathanLeffler注意。谢谢! – raphnguyen

回答

12
    [main] 
       a = 12 
       b = 9 

       fork() 
        | 
        | 
    +--------------+--------------+ 
    |        | 
    |        | 
[parent]      [child] 

fid = 1234      fid = 0 
wait(NULL)      a++ 
    ...       printf("a = 13, b = 9"); 
    ...       return 0 
    ...       <exit> 
b = b - 5 
printf("a = 12, b = 4"); 
return 0 
<exit> 

fork()后,执行有计划的两个副本。每个进程都有自己的变量副本,所以现在有两个a,两个b等等。这两个程序之间的唯一区别是从fork()返回的值:在子进程中fork()返回0;在父进程中,它返回子进程的PID。

子进程增量为a,打印值为ab,然后退出。

父进程首先等待子进程终止。只有在孩子完成后继续,从b减去5,打印出ab,然后退出。

wait(NULL)确保子进程的打印输出始终在父进程之前出现,因此您将始终以可靠的顺序获得相同的输出。没有它,你将无法依靠这两个打印输出的顺序。它们将是相同的信息,只是以不可预测的顺序。

+0

非常感谢!我想知道如何处理需要输出的问题,这样做很有意义,所以正确的输出是'程序退出.a = 13,b = 9',然后是'程序退出。 a = 12,b = 4'? – raphnguyen

3

当您拨打fork()时,包括所有内存/变量等在内的整个过程都会被复制。

所以fork电话后,每个进程都有它的ab它开始分别129自己的副本。

进程0将增加它自己的副本a。过程1将减少(5)它自己的副本b

所以他们应该打印:

Process 0: a = 13, b = 9 
Process 1: a = 12, b = 4 
4
  1. a设置为12,b设定为9

  2. fork叫,我们现在有两个过程。

  3. 父节点获取子节点的PID,并转到else子句。孩子得到0,并转到if子句。

  4. 父母等待孩子完成。

  5. 孩子增加其副本a。所以a现在在孩子中是13岁,在父母中是12岁。

  6. 孩子出口,输出139

  7. 父母从其b副本中减去5,所以b现在在父母中为4。

  8. 父母退出,输出124

注意,孩子和家长的执行fork后的确切顺序是不能保证的,但因为父等待孩子完成它做任何事情之前,它不会改变结果。

另外,请注意,让这两个进程正常退出是不好的做法。当一个进程正常退出时,它会运行清理处理程序,这可能会混淆其他进程,例如,通过更改共享文件描述中的文件位置,导致数据损坏。

+0

非常感谢您的一步一步。在这种情况下,在父进程完成wait()调用之后,你会说它会被阻塞,直到子进程结束(在子进程输出'13'和'9'之后? – raphnguyen

+0

不客气。是的, “等待”电话的目的是阻止父母,直到孩子完成(或不可重新启动的信号中断呼叫) –

+0

晶晰的解释,再次感谢!我希望我的书有更多的练习例子。 – raphnguyen

0

及其O/P是 父:: A = 12,B = 4 儿童::一个= 13,B = 9

既是过程同时执行,但两者都具有局部变量的不同拷贝的,b so local var。受到一个进程的影响将不会被另一个进程看到,因为两个进程都在自己的副本上工作