如何让 Linux 等待我的 C++ 程序完成其清理例程。该程序最初调用函数 sigaction(2)
来注册自定义 SIGTERM 处理程序。如果通过运行 kill -s TERM $(ps -C a.out -o pid=)
测试处理程序,它不会有问题。但是,在真正关机时又是另一种情况。有时处理程序可以完成所有工作,但有时不能。显然,机器关闭时存在竞争条件。有谁知道如何让系统等待更长的时间以避免竞争条件?谢谢。
最佳答案
在评论中您说您使用的是 MX Linux 18.2 版。它似乎是基于默认使用 systemd
的 Debian 9,但如果需要,仍然可以选择恢复到经典的 SysVinit。 MX Linux 的网页似乎强调了 UI,并没有提到任何关于 init 系统的特别之处,所以我假设它也使用 systemd
。
对于 systemd
,一种称为控制组(简称 cgroups)的机制正在发挥作用:当 systemd
启动服务时,它也会将其进程放在一个特殊的 cgroup 中。该 cgroup 由服务启动的任何进程自动继承。当 systemd 停止服务时,它会首先执行任何自定义的 ExecStop
操作,如果为服务定义了任何操作,则等待 TimeoutStopSec
,如果还有剩余的进程在服务的 cgroup 中,systemd
将向它们发送一个 SIGTERM,等待另一个 TimeoutStopSec
,然后将为 cgroup 中的任何剩余进程发送一个 SIGKILL。
让您感到困惑的可能是 用户 session 也被封装在一个 cgroup 中:您手动启动的任何内容,例如sh/etc/init.d/yourservice start
仍将算作用户 session 的一部分,即使它执行了经典守护进程所需的所有操作。因此,当您启动关闭时,第一个操作是注销所有用户 session ......这会导致您手动启动的服务首先收到 SIGHUP,然后在短暂延迟后收到 SIGTERM,并可能在另一次短暂延迟后收到 SIGKILL .清除用户 session 后,将执行其余的关闭过程。
为了在 systemd
中成功使用 init.d
脚本,您需要了解一些事情。
systemd
对 init.d
脚本的兼容性机制通过为每个 自动生成 native systemd
脚本,然后像原生 .service
单元文件来工作init.dsystemd
服务一样使用这些单元文件。这会导致您可能不熟悉的三个要求:
- 您的
init.d
脚本应该在描述与任何其他服务的依赖关系的脚本中的任何非注释行之前有一个 Linux Standard Base 注释 block 。它看起来应该有点像这样(来自 Dovecot IMAP 服务器的示例):
### BEGIN INIT INFO
# Provides: dovecot
# Required-Start: $local_fs $remote_fs $network $syslog $time
# Required-Stop: $local_fs $remote_fs $network $syslog
# Should-Start: postgresql mysql slapd winbind nslcd
# Should-Stop: postgresql mysql slapd winbind nslcd
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Dovecot init script
# Description: Init script for dovecot services
### END INIT INFO
放置
init.d
脚本后,您应该运行systemctl daemon-reload
来触发systemd-sysv- 的重新运行生成器
,生成将调用您的脚本的单元文件。将脚本放置为
/etc/init.d/yourservice
并运行systemctl daemon-reload
后,您应该使用启动服务systemctl start yourservice
或service yourservice start
。只有这些方法会导致systemd
将您的服务置于其自己的控制组中,这对于有序关闭您的服务需求非常重要。运行sh/etc/init.d/yourservice start
不会这样做。
您可以使用 systemctl cat yourservice
查看生成的自动生成的 yourservice.service
单元文件。
为您的服务编写 native systemd 服务单元文件可能是一个更好的主意。您可以在 /lib/systemd/system/
目录中找到发行版的标准单元文件;您可以将它们用作示例,但您应该将自定义单元文件放入 /etc/systemd/system
中,这样您的单元文件就不会被任何包更新覆盖。
关于linux - 如何让 Linux 等到我的程序完成其 SIGTERM 操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56286754/