我正在读《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,而且看起来PID1甚至不是init进程,而是systemd进程.它们有好几个:当我运行pgrep systemd时,它输出1和2754.

现在我很困惑,以下是我的问题:

  • init%的流程在哪里?
  • 为什么会有多个systemd进程?

推荐答案

看起来PID1甚至不是init进程,而是一个系统进程

系统ID进程is初始化进程.它不是与传统init相同的软件,但它仍然可以实现init通常能实现的所有功能(而且还会更多一点;它不仅仅是init的直接重新实现).

尽管"SysV init"在历史上一直是Linux最受欢迎的init,但它从来不是唯一的--它是一个发行版 Select ,所以你还可以 Select init-ng、s6、upstart、system d等.

它们有多个:当我运行pgrep system d时,它输出1和2754.

服务管理并不仅限于init/pid1--尽管pid1由于是缺省父进程而具有一定的优势--但拥有一个执行大致相同任务的"用户级"服务管理器是相当常见的.例如,当您登录到GNOME时,初始进程是GNOME-Session--这只是另一种类型的服务管理器,除了开始监督各种其他GNOME组件外,什么都不做.

因此,系统D自然支持一种模式,在该模式中,它可以作为普通的非PID1进程运行,并为一个特定用户(通过systemctl --user)管理服务.如今,您的大部分图形用户界面环境组件都是以这种方式启动的.

(您并没有在SysV风格的init中真正看到它,因为它的服务管理特性是...缺乏,几乎所有的工作都是通过shell 工具outside init完成的.但UpStart和SYSTEM都直接在PID1内处理服务.)

所以呢,

不仅getppid()没有返回1

正如 comments 中所指出的,Linux现在为独立的服务管理器提供了一个API,使其成为其子进程的新的默认父进程(收割器).Systemd在其"每用户"模式中使用它,以便更轻松地处理试图"守护"(并因此成为孤立的)的服务.

C++相关问答推荐

ISO_C_BINDING,从Fortran调用C

编译SDL 2时缺少SDL_ttf

C:scanf(%d&q;,...)输入只有一个减号

将指针作为参数传递给函数

不会停在空格或换行符上的错误

如何在C中通过套接字自定义数据类型读取原始变量?

为什么我一直收到分段错误?

在列表中插入Int指针(C)

C在声明带有值的数组时,声明大小有用吗?

在另一个函数中使用realloc和指针指向指针

强制转换变量以在 struct 中蚕食

链接到底是如何工作的,我在这里到底做错了什么

是否定义了此函数的行为?

判断系统命令返回值的正确方法

对于STM32微控制器,全局偏移表.get和.Got.plt必须为零初始化

有没有办法减少C语言中线程的堆大小?

C编译和运行

RISC-V GCC编译器错误编译ASM代码

struct 中的qsort,但排序后的 struct 很乱

从系统派生线程调用CRT