Linux:exec()没有fork()?

envsm3lx  于 2023-06-21  发布在  Linux
关注(0)|答案(2)|浏览(115)

当您使用exec() * 而不调用fork() * 时,究竟会发生什么?这样做的含义和可能的注意事项是什么?
通过阅读手册页,我的理解是,执行exec()本质上是在用新的(空白的)进程映像替换调用进程时终止它。问题是,以这种方式终止调用进程是否是使用exit()的常规方式的可行替代方案?
也许我的google-fu已经变形了,但是搜索这个问题主要会导致与更常见的“* fork()without exec()”范式相关的答案,而不是我正在寻找的“ exec()without fork()*”。
什么
我想终止当前进程并执行另一个进程。
如何
常规方法:

  1. fork(),然后立即在子节点上exec(),在父节点上exit()
    fork() is slow,因为我马上退出父进程,所以我肯定不想在执行被调用者之前复制调用进程。
  2. vfork(),然后立即在子节点上exec(),在父节点上exit()
    vfork()fork()的轻量级替代品,可用于创建(基本上)空白进程映像 * 而无需 * 不必要地复制父进程,非常类似于Windows世界中的CreateProcess调用。这是一个更好的选择,适合大多数用例。
如果?

我想终止当前进程,然后执行另一个进程。
为什么
如果我在内存极度匮乏的情况下,甚至vfork()都失败了,我选择了第三个选项,即调用exec()而不使用fork(),这实际上是通过用新进程替换父进程来终止它。
假设我有两个程序,一个shell脚本叫做“* other ”,我的主程序叫做“ program ”。“ other ”位于我的PATH中,因此execlp()被专门使用,而“ other *”调用时没有完整路径。

    • program. c**
void bye(void) {
    while(1) {
        execlp("other", "other", NULL);
        pause(); // we will never reach here when execlp is successful
    }
}
  • /bin/other*
!/bin/sh

echo "Do other stuff here"

在实践中,这似乎工作得很好。
然而,这是我自己想象出来的,我还没有看到任何关于生成这样一个进程的建议,也没有看到任何其他人这样做的例子,这让我相信,以这种方式终止一个进程可能有本质上的“错误”,我错过了。
是的,我知道我可以“在执行vfork()之前在其他地方释放内存,这样它就不会失败”,但这不是问题所在。

jmo0nnb3

jmo0nnb31#

因此,fork/vfork创建一个新进程,然后exec使用该进程ID运行一个新的可执行文件。则由fork父进程来wait()程序退出以消耗子程序的僵尸状态。
使用VM时,fork和vfork之间的启动时间差异最小。在没有VM的系统上,vfork速度明显更快,但在设置管道等时可能会无意中损坏父进程。
如果你想守护一个程序,那么fork/exec,不要等待。如果希望程序在关闭终端会话后继续运行,您可能还需要更改终端会话进程组。
如果直接执行,则新的可执行文件将在与启动程序相同的进程ID中运行,并且启动程序不再存在。如果有一个父进程在等待这个启动器程序死亡,它不知道可执行文件的改变,并且盲目地继续等待这个新的可执行文件退出。
这是经常使用的,例如bash -c ls将启动bash,它将立即执行ls,本身过期。父shell将等待此操作完成,而不知道它现在正在等待/bin/ls

ebdffaop

ebdffaop2#

exec()不会终止进程,它会用新的映像 * 替换 * 当前进程的映像。除了execve() manual page中 * 对进程属性的影响 * 部分列出的属性外,大多数进程属性都保留在新映像中。
有些程序在没有fork()的情况下执行exec(),以修改必须执行新程序的环境。例如nohup

相关问题