睡眠指令不适用于信号处理程序

时间:2020-02-13 13:40:05

标签: c linux signals sleep

void handler ( int sig, siginfo_t * info, void * se)
{

}

int setup_sig(){
    struct sigaction sa;
    sa.sa_sigaction = handler;
    sa.sa_flags = SA_SIGINFO;
    sigfillset(&sa.sa_mask);
    if(-1 == sigaction(SIGCHLD, &sa , NULL)){return 0;} return 1;
}

void main()
{
    printf("before\n");
    setup_sig();
    sleep(3);
    printf("after\n");
}

此代码需要注册以发出信号SIGCHLD,然后休眠3秒钟,然后熄灭。

此代码跳过睡眠指令,为什么?

1 个答案:

答案 0 :(得分:1)

Linux documentation for sleep在底部列出了以下属性:

┌──────────┬───────────────┬─────────────────────────────┐
│Interface │ Attribute     │ Value                       │
├──────────┼───────────────┼─────────────────────────────┤
│sleep()   │ Thread safety │ MT-Unsafe sig:SIGCHLD/linux │
└──────────┴───────────────┴─────────────────────────────┘

在这种情况下,sig:SIGCHLD/linux很重要。根据{{​​3}},其解释如下(我强调):

sig:标有sig作为MT安全问题的功能可能会出于内部目的临时安装信号处理程序,这可能会干扰以冒号标识的信号的其他用途。

通过确保在通话过程中不会发生信号的其他使用,可以解决此安全问题。在调用使用相同临时信号的所有函数时,持有非递归互斥体;建议 在呼叫之前阻止该信号,然后再重置其处理程序。

可以通过sigprocmask调用来阻止信号,例如:

// Need signal.h for this stuff.

sigset_t mask;

if ((sigemptyset(&mask) == -1) || (sigaddset(&mask, SIGCHLD) == -1)) {
    // handle failure here.
}

if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
    // handle failure here.
}

sleep(3);

// Probably need to re-establish CHLD signal handler as well as unmasking.

if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) {
    // handle failure here.
}