在不使用pkill的情况下优雅地退出程序的最佳方式

Best way to exit a program gracefully without using pkill

本文关键字:退出程序 方式 最佳 情况下 pkill      更新时间:2023-10-16

我当前正在使用一个脚本调用pkill来终止我的C++程序。然而,我注意到在使用pkill时,并没有从我的跟踪中调用析构函数。

有没有其他好方法可以让我优雅地退出程序
pkill看起来有点乱,缓冲区中的一些日志没有被记录下来。我希望能够在我的fstream上进行刷新,并通过程序关闭所有资源(而不是依靠O/S来清理我的烂摊子)。

该应用程序全天候运行,没有任何问题,我唯一想停止它的时间是在维护期间。该应用程序没有任何可供我键入exit的用户界面。

您可以通过以下几行为SIGTERM定义一个信号处理程序来实现这一点:

包含块中的某个位置:

#include <signal.h>
#include <stdio.h>

是的,我们正在做i C风格!

在代码的初始化部分:

signal (SIGTERM, handler);

然后定义信号处理程序代码(清除所有内容等):

void handler(int num) 
{
  // we might use this handler for many signals
  switch (num)
  {
    case SIGTERM:
      // clean up code.
      break;
  }
}

现在,当您运行pkill <app>时,其中<app>是可执行文件的名称,handler()的代码将运行。

如果没有开关,默认的SIGTERM信号将发送到应用程序。如果你选择使用不同的信号,你必须确保你发送的信号与你在handler()中"捕获"的信号相同。

相关信息可以通过man 7 signal找到,当然还有man kill

除了Zrvan的答案之外,请注意,只有一组受限的函数才能从信号处理程序中安全地调用。signal(7)手册页和Posix标准要求在信号处理程序内部只能直接或间接调用异步信号安全函数。请注意,printfmalloc在信号处理程序中是不安全的。信号处理程序的代码编写起来很棘手(而且您无法轻松调试它,因为信号发送是不可复制的)。

正如Glibc文档所建议的那样,您的信号处理程序只需设置一个volatile sig_atomic_t变量,您的主循环将对其进行测试和处理。

如果您的应用程序是基于事件的,您还可以决定某个套接字或命名管道专用于控制它。该事件循环(可能使用select(2)或poll(2),甚至使用pselectppoll)可以处理管道或套接字上的控制消息。

您可能对像libevent这样的事件循环库感兴趣。您也可以使用像洋葱或Wt这样的HTTP服务器库。您也可能对SNMP或D-bus感兴趣。

克服信号处理程序限制的一个技巧是让它们在同一进程的管道上写入,例如Qt的doc所建议的。然后事件循环将处理该管道上的读取。

如果您的应用程序是多线程的,那么信号处理就更加棘手。一些信号被传递到单个线程。

除非您修改目标应用程序,否则我看不到任何方法。

考虑以下内容:

int main()
{
   MyClass a;
   while ( true )
   {
   }
}

你必须告诉程序退出循环。但除非你的应用程序上有某种信号处理机制,否则这似乎是不可能的。

你需要这样的东西:

int main()
{
   MyClass a;
   while ( !killSignalReceived() )
   {
   }
}

最好的方法是处理程序中的信号,然后使用kill发送该信号。在信号处理程序中,标记一个将导致主循环结束的标志。