C 程序中的 fork 与 vfork 功能

fork vs vfork functionality in a C program

我正在做一些C练习自学,遇到了以下问题:

A 部分:

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

    int a = 5, b = 8;                                                     
    int v;                                                                

    v = fork();                                                           
    if(v == 0) {                                                          
        // 10                                                             
        a = a + 5;                                                        
        // 10                                                             
        b = b + 2;                                                        
        exit(0);                                                          
    }                                                                     
    // Parent code                                                        
    wait(NULL);                                                           
    printf("Value of v is %d.\n", v); // line a                           
    printf("Sum is %d.\n", a + b); // line b                              
    exit(0);                                                              

} 

b 部分:

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

    int a = 5, b = 8;                                                     
    int v;                                                                

    v = vfork();                                                               
    if(v == 0) {                                                          
        // a = 10                                                         
        a = a + 5;                                                        
        // b = 6                                                          
        b = b - 2;                                                        
        exit(0);                                                          
    }                                                                     
    // Parent code                                                        
    wait(NULL);                                                           
    printf("Value of v is %d.\n", v); // line a                           
    printf("Sum is %d.\n", a + b); // line b                              
    exit(0);                                                              

}

我们必须比较 line aline b 的输出。

a部分的输出是:

Value of v is 79525.
Sum is 13.

b部分的输出是:

Value of v is 79517.
Sum is 16.

出现在a部分,sum是ab的初始声明之和,而在b部分,sum包括子进程内的求和。

我的问题是 - 为什么会这样?

根据这个post:

The basic difference between the two is that when a new process is created with vfork(), the parent process is temporarily suspended, and the child process might borrow the parent's address space. This strange state of affairs continues until the child process either exits, or calls execve(), at which point the parent process continues.

parent process is temporary suspended 的定义对我来说意义不大。这是否意味着对于 1b,程序在父进程运行之前等待子进程完成 运行(因此为什么要对子进程变量求和)?

问题陈述还假设 "the process ID of the parent process maintained by the kernel is 2500, and that the new processes are created by the operating system before the child process is created."

根据这个定义,两个程序的 v 的值是多少?

the parent process is temporarily suspended

基本上,在 child 调用 _exitexec 函数之一之前,parent 进程不会 运行。在您的示例中,这意味着 child 将 运行 并因此在 parent 运行 之前执行求和并执行打印。

至于:

My question is - why is this happening?

首先,你的 b 部分有未定义的行为,因为你违反了 vfork 语义。程序的未定义行为意味着程序不会以可预测的方式运行。见 this SO post on undefined behavior for more details (it includes some C++ but most of the ideas are the same). From the POSIX specs on vfork:

The vfork() function has the same effect as fork(2), except that the behavior is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before successfully calling _exit(2) or one of the exec(3) family of functions.

所以你的 b 部分真的可以做任何事情。但是,您可能会看到 b 部分的输出有些一致。这是因为当您使用 vfork 时,您并没有创建新地址 space。相反,child 进程基本上 "borrows" parent 的地址 space,通常是为了调用 exec 函数之一并创建一个新节目形象。相反,在您的 b 部分中,您使用的是 parent 地址 space。基本上,在 child 调用 exit 之后(这也是无效的,因为它应该调用 _exit),a 很可能等于 10,而 b 很可能等于等于parent中的6。因此,总和为 16,如 b 部分所示。我说 最有可能 因为如前所述,该程序具有未定义的行为。

对于使用 fork 的部分 a,child 获得了自己的地址 space,并且在 parent 中看不到它的修改,因此打印的值为13 (5 + 8).

最后,关于 v 的值,这似乎只是问题所陈述的内容,以使其显示的输出有意义。 v 的值可以是 vforkfork 返回的任何有效值,不必限制为 2500。