systemd 如何处理托管进程子进程的死亡?

systemd 如何处理托管进程子进程的死亡?

如何systemd处理托管进程的子进程的死亡?

假设systemd启动守护进程foo,然后守护进程启动其他三个守护进程:bar1bar2bar3。如果意外终止,会systemd​​采取什么措施吗?根据我的理解,如果您没有通过更改属性来告知,Solaris 上的服务管理工具 (SMF)将被终止或重新启动。行为有什么不同吗?foobar2foostartdignore_errorsystemd

编辑#1:

我编写了一个测试守护进程来测试systemd的行为。调用该守护进程是mother_daemon因为它会生成子进程。

#include <iostream>
#include <unistd.h>
#include <string>
#include <cstring>

using namespace std;

int main(int argc, char* argv[])
{
  cout << "Hi! I'm going to fork and make 5 child processes!" << endl;

  for (int i = 0; i < 5; i++)
    {
    pid_t pid = fork();

    if (pid > 0)
      {
    cout << "I'm the parent process, and i = " << i << endl;
      }
    if (pid == 0)
      {
      // The following four lines rename the process to make it easier to keep track of with ps
    int argv0size = strlen(argv[0]);
    string childThreadName = "mother_daemon child thread PID: ";
    childThreadName.append( to_string(::getpid()) );
    strncpy(argv[0],childThreadName.c_str(),argv0size + 25);

    cout << "I'm a child process, and i = " << i << endl;
    pause();
    // I don't want each child process spawning its own process
    break;
      }
    }
  pause();
  return 0;
  }

这是由一个systemd名为的单元控制的mother_daemon.service

[Unit]
Description=Testing how systemd handles the death of the children of a managed process
StopWhenUnneeded=true

[Service]
ExecStart=/home/my_user/test_program/mother_daemon
Restart=always

mother_daemon.service装置由以下装置控制mother_daemon.target

[Unit]
Description=A target that wants mother_daemon.service
Wants=mother_daemon.service

当我运行sudo systemctl start mother_daemon.target(之后sudo systemctl daemon-reload)时,我可以看到父守护进程和五个子守护进程。

杀死其中一个子项对父项没有影响,但杀死父项(从而触发重新启动)确实会重新启动子项。

停止也结束mother_daemon.targetsudo systemctl stop mother_daemon.target孩子们。

我认为这回答了我的问题。

答案1

事实并非如此。

主进程以正常方式处理其子进程的死亡。

这就是 POSIX 世界。如果进程A分叉了B,并且进程B分叉了C、D和E;那么进程 B 会看到C、D 和 E 终止后的状态。进程 A 不知道 C、D 和 E 发生了什么,这与 systemd 无关SIGCHLDwait()

为了让 A 知道 C、D 和 E 终止,必须发生两件事。

kevent()(人们可以在 BSD 上变得聪明。但这是一个 Linux 问题。)

答案2

systemd有主进程的概念。在 systemd 文档中,这被称为“主服务进程”或简称为“主进程”。

示例 4 中systemd.service 文档介绍了计算时的主要流程Type=forking

Restart=systemd.service 文档中的文档描述与主进程相关的服务启动时的不同可能性。

以下是上面链接的“示例 4”中的关键文本:

systemd 会认为服务正在初始化,而原始程序仍在运行。一旦成功退出并且至少有一个进程保留(并且RemainAfterExit = no),则该服务被视为已启动。

通常,传统守护进程仅包含一个进程。因此,如果原进程终止后只剩下一个进程,systemd 就会认为该进程是服务的主进程。在这种情况下,$MAINPID 变量将在 ExecReload=、ExecStop= 等中可用。

如果存在多个进程,systemd 将无法确定主进程,因此它不会假设存在一个进程。在这种情况下,$MAINPID 将不会扩展为任何内容。然而,如果进程决定写入传统的 PID 文件,systemd 将能够从那里读取主 PID。请相应地设置 PIDFile=。

相关内容