首页 > 解决方案 > 关闭 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 并且如此接近?- 我能做些什么来解决这种行为?

标签: c++linuxsystemd

解决方案


我注意到我的应用程序接收到 2 个甚至 3 个SIGTERM信号,间隔大约 500 毫秒。

这不是 的行为systemd,您可能想验证您的观察结果。

详情请参阅man systemd.kill

   KillMode=

指定如何终止该单元的进程。对照组,过程,混合,无之一。

如果设置为 control-group,则该单元的控制组中的所有剩余进程将在单元停止时被杀死(对于服务:在执行停止命令后,配置为 ExecStop=)。如果设置为进程,则只有主进程本身被杀死。如果设置为混合,则 SIGTERM 信号(见下文)被发送到主进程,而随后的 SIGKILL 信号(见下文)被发送到单元控制组的所有剩余进程。如果设置为 none,则不会杀死任何进程。在这种情况下,只会在单元停止时执行停止命令,否则不会杀死进程。停止后保持活动的进程留在其控制组中,并且控制组在停止后继续存在,除非它为空。

进程将首先通过 SIGTERM 终止(除非要发送的信号通过 KillSignal= 更改)。可选地,紧随其后的是 SIGHUP(如果使用 SendSIGHUP= 启用)。如果在延迟(通过 TimeoutStopSec= 选项配置)之后,进程仍然存在,则使用 SIGKILL 信号重复终​​止请求(除非通过 SendSIGKILL= 选项禁用此功能)。有关详细信息,请参阅 kill(2)。

默认为控制组。


推荐阅读