在信号处理程序中设置标志

时间:2013-09-20 01:18:20

标签: c++ linux unix c++11 posix

在C ++ 11中,在给定一种请求循环(作为Web请求循环的一部分)的情况下,对被捕获的信号执行不安全代码的最安全(并且是最有效的)方法是什么?例如,从linux命令行捕获SIGUSR1:kill -30 <process pid>

可以接受在下一个被触发的请求上运行“不安全代码”,如果在运行不安全代码之前多次触发信号,则不会丢失任何信息。

例如,我目前的代码是:

static bool globalFlag = false;

void signalHandler(int sig_num, siginfo_t * info, void * context) {
    globalFlag = true;
}
void doUnsafeThings() {
    // thigns like std::vector push_back, new char[1024], set global vars, etc.
}
void doRegularThings() {
    // read filesystem, read global variables, etc.
}

void main(void) {

    // set up signal handler (for SIGUSR1) ...
    struct sigaction sigact;
    sigact.sa_sigaction = onSyncSignal;
    sigact.sa_flags = SA_RESTART | SA_SIGINFO;
    sigaction(SIGUSR1, &sigact, (struct sigaction *)NULL);

    // main loop ...
    while(acceptMoreRequests()) { // blocks until new request received
        if (globalFlag) {
            globalFlag = false;
            doUnsafeThings();
        }
        doRegularThings();
    }
}

我知道在主循环测试中可能存在问题+设置globalFlag boolean。

编辑:if (globalFlag)测试将在相当紧密的循环中运行,并且可以接受“偶尔”的假阴性。但是,我怀疑Basile Starynkevitch的解决方案还没有优化呢?

1 个答案:

答案 0 :(得分:6)

你应该声明你的旗帜

  static volatile sig_atomic_t globalFlag = 0;

参见例如sig_atomic_tthis question并且不要忘记volatile限定符。 (C可能拼写为sigatomic_t

在Linux(特别是)上,您可以使用signalfd(2)获取信号的文件描述符,并且fd可以是poll(2) - 由您的事件循环编辑。

某些事件循环库(libeventlibev ...)知道如何处理信号。

还有在初始化时设置管道(请参阅pipe(2)以获取更多信息)的技巧,并在信号处理程序中仅write(2)处理一些字节。事件循环将轮询并读取该管道。

另请阅读signal(7)(它解释了信号处理程序中可用的有限函数或系统调用的内容)....

顺便说一句,正确性比效率更重要。一般情况下,您获得的信号很少(例如,大多数程序最多每秒钟获得一次信号,而不是每毫秒一次)。