exec() 混乱,更像是替换或子程序?

exec() confusion, more like replacement or subroutine?

在下面的 link 以及许多其他类似的地方,exec 通常被描述为:

Differences between fork and exec

The exec call is a way to basically replace the entire current process with a new program. It loads the program into the current process space and runs it from the entry point.

它真的能取代整个程序吗?这不更像是执行一个 subroutine/function 调用,恰好体现了所选程序的 main() 吗? - 在返回到它自己的上下文和操作之前?

那么更恰当的描述是,只是一个体现main()的子程序? (例如,将所选进程代码合并到当前进程中?而不是完全 "replacing it"?

# original taken from the provided link
+--------+
| pid=7  |
| ppid=4 |
| bash   |
+--------+
    |
    | calls fork
    V
+--------+             +--------+
| pid=7  |    forks    | pid=22 |
| ppid=4 | ----------> | ppid=7 |
| bash   |             | bash   |
+--------+             +--------+
    |                      |
    | waits for pid 22     | calls exec to run ls
    |                      V
    |                  +--------+
    |                  | pid=22 |
    |                  | ppid=7 |
    |                  | ls     |
    V                  +--------+
+--------+                 |
| pid=7  |                 | exits
| ppid=4 | <---------------+
| bash   |
+--------+
    |
    | continues
    V

# wouldnt this technically be more accurate?
# or am I misunderstanding something with exec()?
+--------+
| pid=7  |
| ppid=4 |
| bash   |
+--------+
    |
    | calls fork
    V
+--------+             +--------+
| pid=7  |    forks    | pid=22 |
| ppid=4 | ----------> | ppid=7 |
| bash   |             | bash   |
+--------+             +--------+
    |                      |
    | waits for pid 22     | calls exec to run ls
    |                      V
    |                  +--------+
    |                  | pid=22 |
    |                  | ppid=7 |
    |                  | bash   |
    |                  | ls()   |
    |                  +--------+
    |                      |
    |                      | ls completes
    |                      | and the program context returns to bash's
    |                      |
    |                  +--------+
    |                  | pid=22 |
    |                  | ppid=7 |
    |                  | bash   |
    |                  +--------+
    |                      |
    V                      |
+--------+                 | the child branch of bash calls exit/return
| pid=7  |                 | that follows the exec statement in the
| ppid=4 | <---------------+ "if (fork() == 0) {...}" code branch
| bash   |
+--------+
    |
    | continues
    V

现在显然我的理解有误。因为如果我说的话 以上是正确的,那么不应该所有衍生的进程都只是实例 当我查看 htop 时 bash 或 init?他们不是(他们都有自己的名字,例如 ls 或 htop) 那么 exec() 实际上是否用新程序替换了调用它的整个程序?所以就像调用 exec() 隐式杀死调用它的程序?这是怎么回事?

exec 是否 用新程序替换当前程序。该过程被完全覆盖。没有状态留给return了。但是说 exec "implicitly kills" 调用它的进程也不准确。进程继续执行;只是它现在 运行 是一个不同的 程序 。它保留其旧进程 ID。

作为"subroutine"执行新进程的方法是首先fork,然后让子进程执行exec,然后让父进程执行wait用于子进程的终止。这就是当您在 shell 处键入命令时发生的情况。这也是 system 库函数在幕后所做的。

您的理解有误。 exec 系列函数将调用进程完全替换为新进程。事实上,如果一个 exec 函数 returns,则在启动新进程时发生错误。

新进程保留旧进程的进程 ID 以及任何打开的文件描述符。其他的都被替换了。

与"calling"新程序不同。当来自 main 的新程序 returns(或调用 exit)过程结束。它不会 "return" 到调用它的程序。

它真的取代了整个程序吗? 是的,它确实取代了整个程序。可以用它自己替换整个程序,从而从头开始重新启动同一个程序(并部分地给你你似乎有的概念)。

是不是更像是执行一个 subroutine/function 调用,恰好体现了所选程序的 main()? - 在 return 回到它自己的上下文和操作之前? 不。当 exec() 函数族完成它们的工作时,函数永远不会 returns。任何 return 值都表示失败。

fork()exec 系列都是独立的操作,并且有充分的理由独立存在。也就是说,它们经常一起使用,其中 fork() 创建一个新进程,这样:

  • 两者现在都从(有效地)fork() 语句的 return 开始执行(实际上在内核内部某处,这导致两个进程 return 在 fork()语句)
  • 其中一个 returns 0 来自 fork() 而另一个 returns 是新进程的进程 ID
  • 其中一个从 fork() 键入 return,调用 exec(),因为其目的只是在不停止第一个的情况下生成一个新的 process/program。

Does it really replace the entire program though?

是的。

Isnt it just more like executing a subroutine/function call that just happens to embody the main() of the selected program? - before returning back into its own context and operations?

没有

so wouldnt a more appropriate description be, just a subroutine that embodies main()? (e.g. incorporating the chosen processes code into the current proccesses? As opposed to full on "replacing it"?

没有

Now obviously there is a flaw in my understanding. Since if what I have said above is correct, then shouldnt all spawned proccesses be all just instances of bash or init when I look into htop? They arent (they all have their own names e.g. ls or htop)

完全正确。

So does exec() actually replace the entire program that calls it w/ a new one?

是的。

So like calling exec() implicitly kills the program which calls it?

不完全是。它用一个不同的程序替换了程序,正是你读到的,“[i]t 将程序加载到当前进程 space 并从入口点运行它”。

这是个奇怪的问题。你已经准确地描述了一切,然后问它是否真的以你似乎编造的完全不同的方式运作。但是你没有解释为什么你认为它以其他方式起作用。

是的,它按照向您描述的方式工作,而不是您看起来编造的方式。如果出于某种原因您认为描述不正确并且它实际上以其他方式起作用,那么您还没有告诉我们它是什么。