c++ - 关闭 linux systemd 时向我的应用程序发送多个 sigterm 信号
问题描述
我已经为设计为在 linux 上运行的应用程序设置了如下所示的 C++ 信号处理程序:
设置信号处理程序以调用静态函数:
// Setup the SIGNTERM signal handler for kill/pkill or systemd terminate
if (signal(SIGTERM, manager_signal_handler) == SIG_ERR)
{
ERROR << "Failed to add signal SIGTERM to signal handler with error code: " << std::strerror(errno) << ENDL;
}
静态信号处理程序——调用类实例成员函数
static dds_manager_base *p_this_dds_manager_base = nullptr;
static void dds_manager_signal_handler(int signum)
{
if (p_this_manager_base)
{
DEBUG << "static manager_signal_handler calling: p_this_manager_base->signal_handler\n";
p_this_manager_base->signal_handler(signum);
}
else
{
ERROR << "manager_signal_handler - manager pointer not set\n";
}
}
成员函数 - 处理信号:
void dds_manager_base::signal_handler(int signum)
{
DEBUG << "dds_manager_base::signal_handler - received signal: " << signum << ENDL;
// Termination actions - can take 5-10 seconds...
}
我sytemctnl powerdown
用来关闭 linux(这会停止我的应用程序正在运行的服务)。我注意到我的应用程序接收到 2 个甚至 3 个 SIGTERM 信号,间隔大约 500 毫秒。
我可以处理这种情况,但我期望的是 1 个 SIGTERM,如果我的应用程序没有在该时间限制内终止,那么可能会在 90 秒后发出 SIGABRT。
我的问题是,在某些情况下,一旦我处理了信号,我的应用程序已经终止得足够快,以至于我的类不再存在,并且我得到一个核心转储,因为 signal_handler() 函数不再存在。所以我有想法将信号返回到default behaviour signal(SIGTERM, SIG_DFL);
我处理过信号的地方 - 但由于 systemd 调用 SIGTERM 的次数超过了第二次调用std::exit()
(我相信这是默认行为)被调用并在它可以优雅之前终止我的应用程序关闭。
这是我的服务/单元文件:
[Unit]
Description=Invoke script to start the corvus application
After = network.target mnt-appdata.mount
[Service]
Type=idle
ExecStart=/mnt/appdata/deploy/services/start_module.sh ${SYS_NUM} ${DDS_NUM}
[Install]
WantedBy=multi-user.target
您可以看到该脚本start_module.sh
被调用 - 这是然后通过执行以下操作运行我的应用程序:./my-application &
所以我的问题是: - 为什么我得到不止一个 SIGTERM 并且如此接近?- 我能做些什么来解决这种行为?
解决方案
我注意到我的应用程序接收到 2 个甚至 3 个
SIGTERM
信号,间隔大约 500 毫秒。
这不是 的行为systemd
,您可能想验证您的观察结果。
详情请参阅man systemd.kill
:
KillMode=
指定如何终止该单元的进程。对照组,过程,混合,无之一。
如果设置为 control-group,则该单元的控制组中的所有剩余进程将在单元停止时被杀死(对于服务:在执行停止命令后,配置为 ExecStop=)。如果设置为进程,则只有主进程本身被杀死。如果设置为混合,则 SIGTERM 信号(见下文)被发送到主进程,而随后的 SIGKILL 信号(见下文)被发送到单元控制组的所有剩余进程。如果设置为 none,则不会杀死任何进程。在这种情况下,只会在单元停止时执行停止命令,否则不会杀死进程。停止后保持活动的进程留在其控制组中,并且控制组在停止后继续存在,除非它为空。
进程将首先通过 SIGTERM 终止(除非要发送的信号通过 KillSignal= 更改)。可选地,紧随其后的是 SIGHUP(如果使用 SendSIGHUP= 启用)。如果在延迟(通过 TimeoutStopSec= 选项配置)之后,进程仍然存在,则使用 SIGKILL 信号重复终止请求(除非通过 SendSIGKILL= 选项禁用此功能)。有关详细信息,请参阅 kill(2)。
默认为控制组。
推荐阅读
- c# - 如何跟踪哪些代码正在使用 ThreadPool 中的线程
- c++ - 有一个参数字符串问题的构造函数
- scala - 如何在 ZIO Zlayer 依赖项中动态传递数据库名称
- javascript - 将内部跨度添加到 Gutenberg 核心按钮块
- three.js - 当比例不同时,FBX 模型看起来很小。我怎样才能让它看起来一样?
- c++ - 不相关数据无限循环的数据/打印错误
- blazor - 在 Blazor 中,子组件调用在父组件上渲染,因此父组件包含子组件
- ios - Core Graphics - 使用整数数组绘制灰度图像
- json - Microsoft Teams 卡片为 html
- python - 循环置换的组成