我在linux中了解fork()
时遇到了一些问题。
让我感到困惑的是,如果父母提出了一个子进程并且该孩子正在调用execl()
和
execl()
没有返回,父进程等待子进程退出,系统会不会
挂?
提前感谢您的帮助。
这是mdadm的代码示例。因此,在execl()
之后的子进程中有exit(1)
。
如果execl()
没有返回,那么exit(0)
会执行吗?如果没有那么父母会无限期地等待?我在这儿吗?
if (!check_env("MDADM_NO_SYSTEMCTL"))
switch(fork()) {
case 0:
/* FIXME yuk. CLOSE_EXEC?? */
skipped = 0;
for (i = 3; skipped < 20; i++)
if (close(i) < 0)
skipped++;
else
skipped = 0;
/* Don't want to see error messages from
* systemctl. If the service doesn't exist,
* we start mdmon ourselves.
*/
close(2);
open("/dev/null", O_WRONLY);
snprintf(pathbuf, sizeof(pathbuf), "mdmon@%s.service",
devnm);
status = execl("/usr/bin/systemctl", "systemctl",
"start",
pathbuf, NULL);
status = execl("/bin/systemctl", "systemctl", "start",
pathbuf, NULL);
exit(1);
case -1: pr_err("cannot run mdmon. "
"Array remains readonly\n");
return -1;
default: /* parent - good */
pid = wait(&status);
if (pid >= 0 && status == 0)
return 0;
}
答案 0 :(得分:2)
首先,请注意execl
永远不会返回(除非有错误,这意味着execl
失败,即它确实“没有” - 子进程仍然在同一个模块中执行)。
如果父进程等待子进程退出,那么它显然会阻止这样做。然而,这是预期的行为,它与“系统挂起”不同。系统不会挂起。
修改强>
关于编辑问题中发布的代码:首先,使用fork
创建[几乎]完全相同的流程副本。实际上,人们并不关心创建副本,但是人们真的想创建一个 new 进程。但是,在Unix下,新进程是 forked ,而不是创建从头开始。
然后跟两个电话execl
。通常情况下,第一个应该永远不会返回。相反,将加载可执行文件systemctl
以替换子进程,并且子进程将从systemctl
的入口点继续运行(这是一个非常简化的描述,但它基本上就是这样)。登记/>
因此systemctl
将作为一个“新”独立进程运行(实际上,它“偷走”分叉进程!),它(希望)最终会退出,这会导致父进程从{{1 }}
然而,wait
中可能无法找到systemctl
(或发生其他错误)。对于这种情况,上述代码的程序员再次尝试从/usr/bin
加载systemctl
。同样,如果这样做,/bin
将不会返回,但execl
中的代码将执行并最终退出。然后,父进程将从systemctl
取消阻止。
最后,如果对wait
的第二次调用也失败(即返回),则作者放弃并简单地调用execl
,这将返回非零“错误“父母从exit(1)
醒来的代码。
答案 1 :(得分:2)
如果exec
未返回,则表示该进程正在执行某些(新)代码。新代码完全取代旧代码,因此从成功的exec
返回是无稽之谈,因为对exec
的调用在旧代码中。
在此期间,父进程wait
结束其子进程。因此父母将被阻止,直到孩子终止。
答案 2 :(得分:1)
如果某个进程正在等待另一个进程,并且其他进程正在调用exec(),那么获取exec的进程现在是第一个进程正在等待的进程。因此系统不会挂起,如果/当exec'd进程退出时,第一个进程将继续执行。
答案 3 :(得分:0)
没有。每个进程都使用fork()调用启动,然后子进行exec()系列调用{参见man for execl,execlp,execle,execv,execvp,execvpe}。启动后启动的第一个进程是“init”,所有进程都可以使用“ppid”追溯到“init”。