关闭终端窗口与终止/退出有何不同?

关闭终端窗口与终止/退出有何不同?

我正在尝试帮助 AskUbuntu 的用户解决以下问题,

退出终端与关闭终端

语境:-

我正在 bash 中运行一个进程,并&在后台模式下附加 ie。该进程有一个while(1)即它将永远运行。我的 bash 是父进程,我的进程是子进程。我想了解当父进程终止时内核如何处理子进程。

观察结果:-

  1. 如果我退出终端(使用exit终端命令),则/lib/systemd/systemd --user成为子进程的父进程
  2. kill如果我从另一个终端终止终端进程(使用),结果与上面相同
  3. 如果我使用十字图标关闭终端,子进程也会终止

问题:-

关闭与杀死/退出有何不同?

我已经写了一个答案,但觉得我不太明白发生了什么,我认为在 Unix & Linux 上提供帮助的几个人比我更了解并且可以解释发生了什么。

因此,请通过插入并写下答案来帮助我们理解(代替我在 AskUbuntu 上的尝试)。

答案1

1 的答案是systemd --user采用孤儿(即扮演 pid 1 = init 的角色),因为它通过prctl(PR_SET_CHILD_SUBREAPER, 1)在生成其子级之前调用而成为“子收割者”。这是一个 Linux 扩展。

3 的答案是,这取决于终端仿真器。它们的工作方式并不相同。

但一般来说,1,2和3之间的区别在于,在后一种情况下巴什将收到一个SIGHUP信号 [1] 并将其重新发送给其子进程,导致后台进程终止:

shell [即 bash] 在收到SIGHUP.退出前,交互的shell 将 重新发送 SIGHUP 到所有正在运行或已停止的作业。发送停止的作业SIGCONT以确保它们收到 SIGHUP.

这是一个bash 扩展;并非所有 shell 都重新发送SIGHUP信号。具体来说,dash(/bin/shUbuntu 上的)不会做这样的事情。


SIGHUP但是,即使在 1 的情况下,如果后台进程在其进程组中有一个已停止的进程(使用 模拟终端模拟器script),它也可以获得信号:

$ script -q /dev/null -c /bin/bash
$ sh -c 'sleep 1 & kill -STOP $!; echo $$; while sleep 1; do :; done' &
[1] 3317
$ 3317

$ exit
exit
$ ps 3317
  PID TTY      STAT   TIME COMMAND
    # 3317 is dead.

停止了(不是睡眠)sleep进程已删除其父进程。如果你遗漏了这个sleep 1 & kill -STOP $!部分,它就会存活下来。

与前一个不同,这是操作系统的标准功能,而不是 bash 或其他 shell 特有的功能。

[1] bash 将收到一个SIGHUP信号,因为它位于前台进程组中,并且终端仿真器已经破坏了伪终端(导致内核发送SIGHUP)或本身显式发送了SIGHUP

答案2

子进程必须始终有一个父进程(并且每个进程都有一个父进程 PID)。

在前两种情况下,您会杀死父进程,因此您的进程将具有无效的父 ID。 Unix(和Posix)规定init将采用这样的进程(因此PID为1的进程,现在通常是systemd),并且这样的进程会收到一个信号(因此它知道它应该采用新的子进程,或者可能只是杀死它) 。这也是init(因此 systemd)很重要的原因:它可以查看重要进程是否被杀死或孤立,并且可以采取行动)。

第三个案例就更有趣了。注意:在这种情况下,您不会杀死终端,您只是告诉终端退出,这样终端就有时间清理它的东西。

所以现在我们有其他类型的流程,控制组和作业控制。复杂的主题:终端将停止终端部分(输入处理和如何绘制字符),但是终端(现在通常是 pasudoterminal,并且肯定是 x 中的伪终端)将发送SIGHUP到此类进程,告诉它们另一端挂断。通常这相当于杀死此类控制组中的所有进程。程序可能会告诉终端忽略该信号,或处理此类信号以便更好地退出(通常是重置屏幕)。 (nohup实用程序可用于在 SIGHUP 信号的情况下保持进程运行)。

所以区别是: 1 和 2 杀死不能向子进程发送 SIGHUP 的父进程,因此 PID 1 会照顾它们(注意:如果 stdin 和 stdout 不可用,它可能会杀死它,但这取决于父进程)。 3 终端很好的退出,并通知孩子们对方挂断了,一定要顺利处理。

相关内容