exec() System-Call,为什么调用exec()后父进程还在运行?

exec() System-Call, why does the parent process still runs after calling exec()?

我目前正在阅读 OSTEP 并遇到了这段代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

int
main(int argc, char *argv[])
{
    printf("hello world (pid:%d)\n", (int) getpid());
    int rc = fork();
    if (rc < 0) {
        // fork failed; exit
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {
        // child (new process)
        printf("hello, I am child (pid:%d)\n", (int) getpid());
        char *myargs[3];
        myargs[0] = strdup("wc");   // program: "wc" (word count)
        myargs[1] = strdup("p3.c"); // argument: file to count
        myargs[2] = NULL;           // marks end of array
        execvp(myargs[0], myargs);  // runs word count
        printf("this shouldn't print out");
    } else {
        // parent goes down this path (original process)
        int wc = wait(NULL);

        //WHY IS THIS LINE PRINTED OUT??? Call to exec() already 
        //overwrites the original code segment
        printf("hello, I am parent of %d (wc:%d) (pid:%d)\n",
           rc, wc, (int) getpid());
    }
    return 0;
}

这是输出:

hello world (pid:22206)
hello, I am child (pid:22207)
 32 123 966 p3.c
hello, I am parent of 22207 (wc:22207) (pid:22206)
$

The author says: "What it does: given the name of an executable (e.g.,wc), and some arguments (e.g.,p3.c), it loads code (and static data) from that executable and over-writes its current code segment (and current static data) with it; the heap and stack and other parts of the memory space of the program are re-initialized. Then the OS simply runs that program, passing in any arguments as the argv of that process. Thus, it does not create a new process; rather, it transforms the currently running program (formerly p3) into a different running program (wc). After the exec()in the child, it is almost as if p3.c never ran; a successful call to exec()never returns."

加粗的部分是我感到很困惑的地方。据我了解,父进程停在int wc = wait(NULL);行,子进程从int rc = fork();行开始,一直到execvp(myargs[0], myargs);行。之后,调用的可执行文件的代码被加载并覆盖当前代码段,堆栈和堆被重新初始化,将原来的程序转换为不同的 运行 程序,但为什么 hello, I am parent of 22207 (wc:22207) (pid:22206) 仍然在原始代码段被覆盖并且调用 exec() 之后打印出来从不 returns?

当作者说:

"(...) Thus, it does not create a new process; rather, it transforms the currently running program (formerly p3) into a different running program (wc). After the exec()in the child, it is almost as if p3.c never ran; a successful call to exec()never returns."

它们的意思是子进程,而不是父进程,将被 exec() 命令覆盖。这就是为什么不执行exec后子进程中的reaming代码。请记住,子进程代码只是 else if (rc == 0) 子句中的那些行:

else if (rc == 0) {
        // child (new process)
        printf("hello, I am child (pid:%d)\n", (int) getpid());
        char *myargs[3];
        myargs[0] = strdup("wc");   // program: "wc" (word count)
        myargs[1] = strdup("p3.c"); // argument: file to count
        myargs[2] = NULL;           // marks end of array
        execvp(myargs[0], myargs);  // runs word count
        printf("this shouldn't print out");
    }  

还要记住,子进程本身就是一个新进程,有自己的内存段。因此,exec() 命令不会影响其父进程(甚至无法访问其父进程),甚至不会影响来自同一父进程的其他子进程。