我在读《Linux 编程接口》一书,看到这句话(在第 6.2 章末尾):
如果子进程因其“出生”父进程终止而成为孤儿进程,则该子进程将被 init 进程采用,并且子进程中对 getppid() 的后续调用将返回 1。
所以我写了一些代码来查看这一点。这是代码:
#include <unistd.h>
#include <stdio.h>
int main()
{
printf("starting...\n");
if (fork() == 0)
{
printf("Child PID: %d\n",getpid());
printf("Child PPID: %d\n",getppid());
printf("sleeping till the parent die:(\n");
sleep(5);
printf("Child new PPID: %d\n",getppid());
}
else
{
printf("Parent PID: %d\n",getpid());
}
return 0;
}
运行代码后,我得到以下输出:
starting...
Parent PID: 16577
Child PID: 16578
Child PPID: 16577
sleeping till the parent die:(
Child new PPID: 2754
不仅
getppid()
不返回1,看起来PID 1甚至不是init
进程,而是一个systemd
进程。其中有多个:当我运行 pgrep systemd
时,它会输出 1 和 2754 等。
现在我很困惑,这些是我的问题:
init
流程在哪里?systemd
进程?看起来PID 1甚至不是init进程,而是一个systemd进程
systemd 进程是init 进程。它与传统 init 不是同一个软件,但它仍然执行 init 通常执行的所有功能(甚至更多;它不仅仅是 init 的直接重新实现)。
虽然“SysV init”历来是 Linux 上最流行的 init,但它从来都不是唯一的 – 它是一个发行版选择,所以你还有 init-ng、s6、Upstart、systemd 等。
其中有多个:当我运行 pgrep systemd 时,它输出 1 和 2754 等。
服务管理并不只限于 init/pid1——尽管 pid1 由于是默认父级而具有一定的优势——但有一个“用户级”服务管理器做大致相同的事情是相当常见的。例如,当您登录 GNOME 时,第一个进程是 gnome-session – 它只是另一种服务管理器,除了开始监督各种其他 GNOME 组件之外什么也不做。
因此,systemd 自然支持一种模式,可以作为普通的非 pid1 进程运行并为一个特定用户管理服务(通过
systemctl --user
)。如今,您的大部分 GUI 环境组件都是通过这种方式启动的。
(你并没有真正在 SysV 风格的 init 中看到它,因为它的服务管理功能......缺乏,几乎所有事情都是通过 shell 工具outside init 正确完成的。但是 Upstart 和 systemd 都直接在 pid1 内处理服务。)
因此,
getppid() 不仅不返回 1
正如评论中所指出的,Linux 现在为独立服务管理器提供了一个 API,使其成为其子进程的新默认父进程(收割者)。 Systemd 在其“每用户”模式下使用此功能是为了更轻松地处理尝试“守护进程”(并因此成为孤立的)的服务。