库定义中如何实现默认的SIGINT处理程序?

时间:2019-05-10 06:53:45

标签: c linux signals

目标:如果由于某些奇怪的原因导致程序挂起/卡住,请将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处理程序会导致在上述情况下不写入日志消息?

2 个答案:

答案 0 :(得分:2)

default SIGINT handler terminates the process abnormallyThis means _exit被调用,它不会刷新缓冲区。

作为一个旁注,从信号处理程序中调用exit(确实是刷新缓冲区)是不安全的(only async-safe functions should be called from signal handlers)。因此,这不是解决您问题的真正方法。

即使您确实希望在日志文件中显示fflush(fp);,也可以在fprintf之后添加#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 */ }

但是冲洗可能是相当昂贵的。如果您希望避免刷新每条日志行,但仍然希望在接收SIGINT时刷新日志文件,则一种方法是:

Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: org/netbeans/lib/awtextra/AbsoluteLayout

....
....

Caused by: java.lang.ClassNotFoundException: org.netbeans.lib.awtextra.AbsoluteLayout
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    ... 17 more

关键是真正的清理(通常不是异步安全的)不会在信号处理程序本身中发生。

答案 1 :(得分:2)

默认情况下,Stdio文件缓冲区是块缓冲的,当它崩溃时,它不会刷新文件缓冲区,因此缓冲的输出会丢失。

一种解决方案是在每个<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="content"> <div id="links"> <h1><a>link1</a></h1> <div><h2><a> link2</a></h2></div> <div><h2><a> link3</a></h2></div> <div><h2><a> link4</a></h2></div> <div><h2><a> link5</a></h2></div> <div><h2><a> link6</a></h2></div> <div><h2><a> link7</a></h2></div> </div> </body>之后调用fflush(fp),但这很繁琐。

另一种解决方案是在打开文件后立即使用setvbuf将文件设置为行缓冲模式,以便它为您刷新每个换行符号上的缓冲区:

fprintf(fp, ...)

这也使fp = fopen(FILE_NAME, "w+"); setvbuf(fp, NULL, _IOLBF, BUFSIZ); 立即和逐行输出,而不是延迟输出和成块输出。