Linux 启动和观看另一个进程的最佳实践

Linux best practice to start and watch another process

在我的流程中,我需要 start/restart 另一个流程。 目前我使用一个堆栈大小很小的线程和以下代码:

void startAndMonitorA()
{
  while(true)
  {
    system("myProcess");
    LOG("myProcess crashed");
    usleep(1000 * 1000);
  }
}

我觉得这不是最佳做法。我不知道 std::system() 调用正在阻塞或浪费的资源。我使用的是嵌入式 Linux - 所以总的来说,我尽量关心资源。

一个有问题的部分是立即重新启动:如果子进程无法启动,将导致 100% CPU 使用率。它可能是子进程中的暂时性错误(例如,无法连接到服务器)。在尝试重新启动之前添加至少一秒钟的暂停可能是个好主意。


system 调用对 Linux 的作用是:

  1. 设置要忽略的信号 SIGINTSIGQUIT
  2. 屏蔽信号SIGCHLD
  3. fork()
  4. 子进程调用 exec() shell,将命令行传递给 shell。
  5. 父进程调用 waitpid() 阻塞线程直到子进程终止。
  6. 父进程恢复其信号配置。

如果您要重新实现 system 的功能,您可能会省略第 5 步(以及第 1、2 和 6 步)以避免阻塞线程并依赖 SIGCHLD当子进程终止并需要重新启动时收到通知。

换句话说,最低限度是为 SIGCHLD 设置一个信号处理程序并调用 forkexec

所示代码适用于大多数情况。如果您真的关心资源使用情况,您应该意识到您正在为您正在监视的每个进程启动(并保持)一个线程。如果您的程序无论如何都有一个事件循环,那么可以通过一些额外的努力(并增加复杂性)来避免这种事情。

实现这一点需要以下内容:

  • 而不是调用 system(),而是使用 fork()exec() 来启动外部程序。将其 PID 存储在全局 table.
  • 设置一个 SIGCHLD 处理程序来通知事件循环 child 的退出,例如通过向事件循环监视的管道写入一个字节。
  • 当 child 退出时,运行 waitpidWNOHANG 标志在循环中 运行s 只要有 child仁有所得。 waitpid() 将 return 退出的 child 的 PID,以便您知道从 table 中删除其 PID,并安排重新启动它的超时。