c - 默认 SIGINT 处理程序如何在其库定义中实现?
问题描述
目标:写入This line must be printed
日志文件mib_log_test
以防程序由于某些奇怪的原因挂起/卡住。
为简单起见,写了一个 C 程序如下:
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "./mib_log_test"
FILE *fp = NULL;
int main()
{
fp = fopen(FILE_NAME, "w+");
if (fp == NULL) {
fprintf(stderr, "Unable to open %s file", FILE_NAME);
exit(EXIT_FAILURE);
}
fprintf(fp, "This line must be printed\n");
while(1);
return 0;
}
上面的程序编译运行后,永远不会因为无限循环而自行终止。所以我必须按下ctrl + c
终止它。ctrl + c
我没有看到写在This line must be printed
我的日志文件中(mib_log_test
)
如果我如下所示覆盖默认的 SIGINT 处理程序,This line must be printed
则会写入我的日志文件(mib_log_test
)。
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#define FILE_NAME "./mib_log_test"
FILE *fp = NULL;
void sigint_handler(int sig_num)
{
exit(EXIT_FAILURE);
}
int main()
{
fp = fopen(FILE_NAME, "w+");
if (fp == NULL) {
fprintf(stderr, "Unable to open %s file", FILE_NAME);
exit(EXIT_FAILURE);
}
signal(SIGINT, sigint_handler);
fprintf(fp, "This line must be printed\n");
while(1);
return 0;
}
问题:什么默认的 SIGINT 处理程序会导致在上述情况下不写入日志消息?
解决方案
默认的SIGINT 处理程序异常终止进程。这意味着 _exit
被调用,它不会刷新缓冲区。
作为旁注,从信号处理程序调用exit
(它会刷新缓冲区)是不安全的(只能从信号处理程序调用异步安全函数)。因此,这不是您问题的真正解决方案。
fflush(fp);
如果您真的希望它出现在日志文件中,您可以在之后添加一个fprintf
,即使进程异常终止也是如此。
然而,冲洗可能相当昂贵。如果您想避免必须刷新每个日志行,但仍希望在接收 SIGINT 时刷新日志文件,一种方法是:
#include <signal.h>
static volatile sig_atomic_t keepRunning = 1;
void sigHandler(int sig) {
keepRunning = 0;
}
int main(void) {
signal(SIGINT, sigHandler);
while (keepRunning) {
/* normal operation, including logging */
}
/* cleanup */
return 0; /* this will close (and thus flush) the log file */
}
关键是实际的清理(通常不是异步安全的)不会发生在信号处理程序本身中。
推荐阅读
- java - 无法从 Spring Boot 在 ReactJS 中显示 Base64 图像?
- c# - 如何从 Ubuntu VS C# 代码访问远程 Windows SQL Server Express
- java - 如何从逗号“,”和java中的任何字母之间的字符串中删除空格
- c# - 错误 CS1002: ; 预期,但我想我有分号。我不知道怎么了
- amazon-cloudformation - 注册时唯一的用户名和唯一的电子邮件放大 Cognito React
- git - 将从一个提交中删除的多个文件恢复到之前提交中的状态(批量)?
- python - 处理驻留在列表中的元组列表中的数据
- reactjs - 在开发中使用 Google Auth
- markdown - pdf 的 Markdown 标题
- git - git commit 失败无法运行 gpg2