所以我知道当我在 shell 中运行可执行文件时,shell 会将其分叉为子进程,然后执行以获取可执行文件的程序和数据内存。因此,如果我的 shell 现在关闭/退出,那么其所有关联的子进程也会被终止。
我读到,在 Linux 中,每个进程都是通过 fork() exec() 创建的。我很好奇,想知道每当通过双击图标启动应用程序时,哪个进程 forks() exec() 它,我理解它是某个 OS 进程,我想知道哪个
谢谢你!
回答 追溯到 /sbin/upstart
答案1
首先,术语。
可执行文件是系统中的简单文件。进程就是执行可执行文件中嵌入的程序的简单过程。
你说得对可执行文件的启动方式:
以图形界面为例,您在其中双击一个可执行图标,然后您就可以从显示所单击图标的进程中分叉出可执行文件,其源代码基本上如下:
const char *exe_path = taken_from_icon();
int pid = fork();
if(pid == 0)
{
// I am the new child
execl(exe_path, exe_path, NULL);
// exec only return in case of failure
exit(EXIT_FAILURE);
}
// I am the graphical interface,
// Continue and wait for another clic
但死亡和父母身份孩子的情况并不像你所说的那样。
基本上 — — 当父进程仍然存在时 — — 子进程是其父进程的子进程(是的!-) 它的 PPID(父进程 ID)设置为分叉它的仍然存在的进程。
当父进程死亡时,情况会发生变化。子进程继续存在,但其 PPID 被设置为仍处于活动状态的祖父进程。由于init
进程永远不会死亡,因此总会有一个。
当 shell 本身死亡时,shell 子进程也会死亡,这是很特殊的一件事。我认为有两个原因:
第一个:shell 通常会维护它所分叉的 PID 列表。当 shell 死机时,它会杀死所有 PID。主流 shell 有一个
disown
内置命令,用于从此列表中删除子进程,并在 shell 死机时让其存活。请参阅bash 手册页:默认情况下,shell 在收到 SIGHUP 后退出。在退出之前,交互式 shell 会将 SIGHUP 重新发送给所有正在运行或已停止的作业。已停止的作业将收到 SIGCONT 以确保它们收到 SIGHUP。要防止 shell 向特定作业发送信号,应使用 disown 内置命令将其从作业表中删除(请参阅下面的 SHELL 内建命令),或使用 disown -h 将其标记为不接收 SIGHUP。
第二种:shell 子进程通常通过管道将其 stdin、stdout 和 stderr 连接到 shell 本身。如果 shell 停止使用子进程的 stdout(通常用于打印),或关闭其管道末端,则子进程在向其 stdout 写入时可能会失败,从而可能将其阻塞或终止。