linux - 如何让 Linux 等到我的程序完成其 SIGTERM 操作?

标签 linux sigterm

如何让 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 脚本,您需要了解一些事情。

systemdinit.d 脚本的兼容性机制通过为每个 自动生成 native systemd .service 单元文件来工作init.d 脚本,然后像原生 systemd 服务一样使用这些单元文件。这会导致您可能不熟悉的三个要求:

  • 您的 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 yourserviceservice 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/

相关文章:

c - syslog.h中的 "0-big number"是什么意思?

c++ - std::thread 被杀死后该怎么办?

c++ - 在 OSx 中处理 sigterm

linux - 如果我在 Bash 中创建一个菜单,命令样式历史是可能的

c - 使用 gcc -Q -v "options enabled"和 "options passed"有什么区别

linux - 从 Kernel oops PC 中查找行号

scala - Ubuntu服务随 “Main Process exited, status 143/n/a”随机停止

Linux 2.6.23 。接收错误。读取函数返回-1

c - 即使我在 Linux(Mint 18.3)上使用 kill 命令发送信号,WIFSIGNALED 也会返回 false

捕获 SIGTERM,并 sleep 阻止它工作