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

pat*_*ato 3 c++ unix linux posix c++11

在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道在主循环测试中可能存在问题+设置globalFlag布尔值.

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

Bas*_*tch 6

你应该申报你的国旗

  static volatile sig_atomic_t globalFlag = 0;
Run Code Online (Sandbox Code Playgroud)

参见例如sig_atomic_t,这个问题 并且不要忘记volatile限定符.(它可能是sigatomic_t为C 拼写的).

在Linux(特别是)上,您可以使用signalfd(2)获取信号的文件描述符,并且fd可以由事件循环进行轮询(2).

一些事件循环库(libevent,libev ...)知道如何处理信号.

在初始化时还有设置管道(参见pipe(2)以获取更多信息)的技巧,只需在信号处理程序中写入(2) -s上的某个字节.事件循环将轮询并读取该管道.

同时读取信号(7)(它解释了信号处理程序中可用的有限功能或系统调用的内容)....

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