当您使用exec() * 而不调用fork() * 时,究竟会发生什么?这样做的含义和可能的注意事项是什么?
通过阅读手册页,我的理解是,执行exec()本质上是在用新的(空白的)进程映像替换调用进程时终止它。问题是,以这种方式终止调用进程是否是使用exit()
的常规方式的可行替代方案?
也许我的google-fu已经变形了,但是搜索这个问题主要会导致与更常见的“* fork()without exec()”范式相关的答案,而不是我正在寻找的“ exec()without fork()*”。
什么
我想终止当前进程并执行另一个进程。
如何
常规方法:
fork()
,然后立即在子节点上exec()
,在父节点上exit()
。
fork() is slow,因为我马上退出父进程,所以我肯定不想在执行被调用者之前复制调用进程。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()之前在其他地方释放内存,这样它就不会失败”,但这不是问题所在。
2条答案
按热度按时间jmo0nnb31#
因此,fork/vfork创建一个新进程,然后exec使用该进程ID运行一个新的可执行文件。则由fork父进程来wait()程序退出以消耗子程序的僵尸状态。
使用VM时,fork和vfork之间的启动时间差异最小。在没有VM的系统上,vfork速度明显更快,但在设置管道等时可能会无意中损坏父进程。
如果你想守护一个程序,那么fork/exec,不要等待。如果希望程序在关闭终端会话后继续运行,您可能还需要更改终端会话进程组。
如果直接执行,则新的可执行文件将在与启动程序相同的进程ID中运行,并且启动程序不再存在。如果有一个父进程在等待这个启动器程序死亡,它不知道可执行文件的改变,并且盲目地继续等待这个新的可执行文件退出。
这是经常使用的,例如
bash -c ls
将启动bash,它将立即执行ls,本身过期。父shell将等待此操作完成,而不知道它现在正在等待/bin/ls
。ebdffaop2#
exec()
不会终止进程,它会用新的映像 * 替换 * 当前进程的映像。除了execve() manual page中 * 对进程属性的影响 * 部分列出的属性外,大多数进程属性都保留在新映像中。有些程序在没有
fork()
的情况下执行exec()
,以修改必须执行新程序的环境。例如nohup。