在 Linux 下,程序通过在 crashhandler 中捕获异常(例如在 segfault 上)在崩溃时重新启动自己的最佳方法是什么?
7 回答
最简单的是
while [ 1 ]; do ./program && break; done
基本上,你运行程序直到它返回 0,然后你就中断了。
SIGSEGV
可以被捕获(参见man 3 signal
或man 2 sigaction
),并且程序可以exec
在自身上调用函数族之一以重新启动。对于大多数运行时崩溃 ( SIGFPE
, SIGILL
, SIGBUS
, SIGSYS
, ...) 也是如此。
不过,在这样做之前,我会考虑一下。对于 unix 程序来说,这是一种相当不寻常的策略,您可能会让您的用户感到惊讶(也不一定以令人愉快的方式)。
在任何情况下,如果您想在死前清理任何资源,请确保不要自动重启,否则愤怒的用户会使用并且您会留下一团糟。SIGTERM
SIGKILL
你可以有一个循环,你基本上在其中fork()
做真正的工作,然后等待孩子并检查它在父母中的退出状态。您还可以使用以类似方式监视和重新启动程序的系统,例如 daemontools、runit 等。
作为对这里提出的内容的补充:
另一种选择是像 getty 守护进程那样做。请参阅 /etc/inittab 和相应的 inittab(5) 手册页。似乎它是最全系统的平均值;-)。
它可能看起来像下面的文件片段。明显的优势,这种方法是非常标准的,它允许通过运行级别控制你的守护进程。
# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
进程无法自行重新启动,但您可以使用诸如crontab(1)
安排脚本之类的实用程序来定期检查进程是否仍处于活动状态。
程序本身显然不应该检查它是否正在运行:)
大多数企业解决方案实际上只是从给定字符串中提取输出的奇特方式ps()
,并在满足某些条件时执行操作 - 即,如果找不到您的流程,则调用启动脚本。
如果它特定于段错误,请尝试以下代码。这可以根据需要进行修改。
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <poll.h>
sigjmp_buf buf;
void handler(int sig) {
siglongjmp(buf, 1);
}
int main() {
//signal(SIGINT, handler);
//register all signals
struct sigaction new_action, old_action;
new_action.sa_handler = handler;
sigemptyset (&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction (SIGSEGV, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction (SIGSEGV, &new_action, NULL);
if (!sigsetjmp(buf, 1)){
printf("starting\n");
//code or function/method here
}
else{
printf("restarting\n");
//code or function/method here
}
while(1) {
poll(NULL,0,100); //ideally use usleep or nanosleep. for now using poll() as a timer
printf("processing...\n");
}
return 0; //or exit(SUCESS)
}