我有一个小程序打开一个文件并对其进行一些操作。我将文件关闭订阅到程序终止,如下所示:
static
void exit_handler (int ev, void *arg)
{
fprintf(stderr, "bye %d\n", WEXITSTATUS(ev));
fclose((FILE *)arg);
}
int main (int argc, char *argv[])
{
FILE *out;
...
out = fopen(argv[1], "wt");
if (out == NULL) {
perror("Opening output file");
exit(EXIT_FAILURE);
}
on_exit(exit_handler, out);
...
}
尝试执行此操作我注意到只有在程序正常终止时它才能正常工作。如果 CTRL + C (SIGINT
),则不会执行exit_handler
回调。
这不奇怪吗?我应该将exit(EXIT_FAILURE)
调用关联到SIGTERM
的信号处理程序吗?在这种情况下,最佳做法是什么?
答案 0 :(得分:4)
首先,on_exit
不是由POSIX指定的(atexit
具有相同的语义)。其次,linux手册说:
on_exit()函数注册要调用的给定函数 正常流程终止,无论是通过exit(3)还是通过return返回 该计划的主要()。
被信号杀死不是进程的正常退出,因此安装on_exit
和atexit
的回调不会被隐式调用。
答案 1 :(得分:3)
on_exit
信号调用 SIGTERM
。您需要使用signal
为其添加处理程序。例如:
void signalHandler(void)
{
...
}
int main(void)
{
signal(SIGTERM, signalHandler);
}
另请注意,SIGKILL
无法通过设计捕获。
答案 2 :(得分:3)
不,实际上你想要的是不可能的。 Ctrl + C生成的信号是异步,这意味着它可能发生在程序中的任何两个机器指令之间,具体取决于Ctrl + C何时被击中。因此,除非您的程序完全避免在主程序流中的任何地方调用异步信号不安全函数,否则从信号处理程序调用异步信号不安全函数是非法的。 exit
是异步信号不安全的,就像它执行的大多数默认清理活动一样(如刷新/关闭打开的文件)。我希望你要注册的atexit
函数(atexit
,而不是on_exit
,这个函数的正确名称)也想要做异步信号不安全的事情。
如果您需要在退出时根据信号执行清理,则需要安装一个不exit
本身的信号处理程序,而是设置一个全局易失性标记,主程序流将在以后检查(和exit
如果确实如此)。
答案 3 :(得分:2)
来自on_exit
的{{3}},
on_exit()函数注册要调用的给定函数 正常的过程终止,无论是通过退出(3)还是通过返回 程序的主要()。
因此,您需要使用man page中的特定函数明确地为SIGTERM
添加处理程序
的内容
struct sigaction action;
memset (&action, 0, sizeof(action));
action.sa_handler = sigterm_handler;
if (sigaction(SIGTERM, &action, 0))
{
perror ("sigaction");
return 1;
}
/* SIGTERM handler. */
static void sigterm_handler (int sig)
{
...
}