sigsuspend解决时序竞态问题
- 使用pause()函数, 会导致在恢复信号集之前程序挂起
#include <unistd.h> #include <signal.h> #include <stdio.h> void handler(int sig) //信号处理函数的实现 { printf("SIGINT sig\n"); } int main(void) { sigset_t new,old; struct sigaction act; act.sa_handler = handler; //信号处理函数handler sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, 0); //准备捕捉SIGINT信号(注册) sigemptyset(&new); sigaddset(&new, SIGINT); sigprocmask(SIG_BLOCK, &new, &old); //将SIGINT信号阻塞,同时保存当前信号集 printf("Blocked\n"); //模拟阻塞了SIGINT pause(); // 因为之前阻塞了SIGINT, 所以SIGINT在挂起期间永远不会递达, 程序将永久挂起 sigprocmask(SIG_SETMASK, &old, NULL); //恢复原阻塞信号集 printf("sigprocmask recovered\n"); return 0; }
- 使用sigsuspend()函数在程序挂起期间临时撤销对wait信号集中的SIGUSR1以外的信号阻塞(只临时阻塞SIGUSR1), 在挂起期间, 程序可以对除SIGUSR1以外的信号(如SIGINT)进行处理, 执行sigaction
- sigsuspend实际是将临时阻塞SIGUSR1和pause结合起来原子操作
- 临时替换信号集wait和挂起是一个原子操作
#include <unistd.h> #include <signal.h> #include <stdio.h> void handler(int sig) //信号处理函数的实现 { printf("SIGINT sig\n"); } int main(void) { sigset_t new,old, wait; struct sigaction act; act.sa_handler = handler; //信号处理函数handler sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, 0); //准备捕捉SIGINT信号 sigemptyset(&new); sigaddset(&new, SIGINT); //sigprocmask作用: 改变当前进程的阻塞信号集 sigprocmask(SIG_BLOCK, &new, &old); //将SIGINT信号阻塞(模拟Ctrl+c失效),同时保存当前信号集 printf("Blocked\n"); // 模拟阻塞SIGINT(Ctrl+c), 模拟失去cpu sigemptyset(&wait); sigaddset(&wait, SIGUSR1); //pause(); 是挂起期间对所有信号都响应 // 在程序挂起期间对wait(SIGUSR1)临时不响应, 而响应其他所有信号,如SIGINT, 挂起结束后恢复. // 程序挂起期间可以不想被SIGUSR1打断 // 挂起期间可以用SIGINT(Ctrl+c)唤醒进程 sigsuspend(&wait); sigprocmask(SIG_SETMASK, &old, NULL); //恢复原阻塞信号集 printf("sigprocmask recovered\n"); return 0; }