在开发板ubuntu 18.04 arm64上调试部署modbus边缘采集的communicator模块,遇到进程没有优雅的退出,线程的清理工作没有完成。

需求:

  1. 在开发环境中,在终端中手动运行程序,ctrl+c结束进程,所有线程都需要执行清理工作后进程退出
  2. 在生产环境中,将程序部署为ubuntu的服务,通过systemctl stop命令结束进程,所有线程都需要执行清理工作后进程退出

问题1:在终端中手动运行程序,然后ctrl+c,程序没有优雅的退出,所有线程都没有执行清理工作。

解决办法:在linux终端中按下ctrl+c,系统会给正在运行的进程发送SIGINT信号,在代码中处理SIGINT信号,让子线程响应该信号,从而完成退出的工作

signal(SIGINT, sigint_handler);
QSignalMapper signalMapper;
QObject::connect(&a, &QCoreApplication::aboutToQuit, &signalMapper, QOverload<>::of(&QSignalMapper::map));
signalMapper.setMapping(&a, SIGTERM);
QObject::connect(&signalMapper, QOverload<int>::of(&QSignalMapper::mapped), &a, &QCoreApplication::quit);

问题2:通过systemctl stop命令结束进程,查看journalctl日志,所有线程没有执行清理工作(应该是来不及执行清理工作)

解决办法:systemctl stop命令,系统默认会给正在运行的服务进程发送SIGTERM信号,在代码中处理SIGTERM信号,让子线程响应该信号,从而完成退出的工作

signal(SIGINT, sigint_handler);
signal(SIGTERM, sigint_handler);
QSignalMapper signalMapper;
QObject::connect(&a, &QCoreApplication::aboutToQuit, &signalMapper, QOverload<>::of(&QSignalMapper::map));
signalMapper.setMapping(&a, SIGINT);
signalMapper.setMapping(&a, SIGTERM);
QObject::connect(&signalMapper, QOverload<int>::of(&QSignalMapper::mapped), &a, &QCoreApplication::quit);

总结:

chatGPT:

Ctrl+C 组合键在 Linux 终端中用来发送 SIGINT 信号给正在运行的进程,以请求其终止。这是 Linux 系统的一个通用行为,不受具体的发行版影响。SIGINT 信号是中断信号,通常被用来请求进程优雅地终止,允许它执行清理工作。

systemctl stop 命令默认会发送 SIGTERM 信号给指定的系统服务,请求其优雅地终止。这与 Ctrl+C 发送的 SIGINT 信号有所不同。SIGTERM 信号也是一种终止信号,但与 SIGINT 不同,它是正常的终止请求,不会中断进程的执行,而是让进程在收到信号后自行进行清理工作并安全地关闭。

Gemini:

SIGTERM 和 SIGINT 都是用于通知进程终止的信号,但它们之间存在一些关键差异:

产生方式:

  • SIGINT: 通常由用户按下键盘上的 Ctrl+C 键产生。
  • SIGTERM: 可以通过以下几种方式产生:
    • 使用 kill 命令向进程发送信号。
    • 由其他进程发送。
    • 由系统本身发送,例如当系统资源不足时。

默认行为:

  • SIGINT: 通常会导致前台进程立即终止。
  • SIGTERM: 会导致进程以 正常 方式终止。这意味着进程应该有机会进行清理工作,例如关闭打开的文件和释放资源。

可控性:

  • SIGINT: 通常 不可控。这意味着进程无法捕获或忽略 SIGINT 信号。
  • SIGTERM: 通常 可控。这意味着进程可以捕获和处理 SIGTERM 信号。例如,进程可以选择忽略 SIGTERM 信号,或者在终止之前执行一些清理工作。

强制性:

  • SIGINT: 是一个 非强制 信号。这意味着进程可以选择忽略 SIGINT 信号并继续运行。
  • SIGTERM: 是一个 信号。这意味着进程通常会响应 SIGTERM 信号并终止,但它 可以选择 忽略该信号。

SIGKILL 信号:

值得注意的是,还存在 SIGKILL 信号,它与 SIGTERM 和 SIGINT 信号不同。SIGKILL 是一个 信号,这意味着进程 无法 忽略它。SIGKILL 信号用于在进程无响应 SIGTERM 信号或其他终止信号的情况下强制终止进程。