C语言中sigset无法阻塞SIGUSR1信号的问题求助
你编写代码尝试用sigaction的sa_mask实现信号阻塞:为SIGINT设置处理函数,同时在其sa_mask中添加SIGUSR1,期望处理SIGINT时阻塞SIGUSR1;另外为SIGUSR1设置处理函数,主循环中定时用raise()发送SIGUSR1。但实际运行时,按下Ctrl+C后,SIGUSR1仍会被触发,输出交替出现"ctrl c"和"user sig"。
代码重现
#include <stdio.h> #include <unistd.h> #include <signal.h> void handler(int sig) { printf("ctrl c\n"); } void handler1(int sig) { printf("user sig\n"); } int main() { struct sigaction a; a.sa_handler = &handler; sigemptyset(&a.sa_mask); sigaddset(&a.sa_mask, SIGUSR1); a.sa_flags = 0; struct sigaction b; b.sa_handler = &handler1; sigemptyset(&b.sa_mask); b.sa_flags = 0; sigaction(SIGINT, &a, NULL); sigaction(SIGUSR1, &b, NULL); while (1) { sleep(1); raise(SIGUSR1); } return 0; }
问题原因
你误解了sa_mask的作用范围:sigaction的sa_mask仅在当前信号的处理函数执行期间生效,也就是只有当SIGINT的handler函数正在运行时,SIGUSR1才会被阻塞。
你的代码中,每次按下Ctrl+C触发SIGINT后,handler函数执行完毕就会返回主循环,主循环里立刻调用raise(SIGUSR1)发送信号,此时sa_mask已经失效,所以SIGUSR1会被正常处理,导致输出交替出现。
解决方案
如果你希望在处理SIGINT的过程中(包括处理完成后一段时间)阻塞SIGUSR1,有两种常见实现方式:
方式1:用全局标志控制主循环的SIGUSR1发送
#include <stdio.h> #include <unistd.h> #include <signal.h> volatile sig_atomic_t block_usr1 = 0; void handler(int sig) { printf("ctrl c\n"); block_usr1 = 1; // 模拟阻塞SIGUSR1的时长 sleep(3); block_usr1 = 0; } void handler1(int sig) { printf("user sig\n"); } int main() { struct sigaction a; a.sa_handler = &handler; sigemptyset(&a.sa_mask); sigaddset(&a.sa_mask, SIGUSR1); // 确保handler执行期间SIGUSR1被阻塞 a.sa_flags = 0; struct sigaction b; b.sa_handler = &handler1; sigemptyset(&b.sa_mask); b.sa_flags = 0; sigaction(SIGINT, &a, NULL); sigaction(SIGUSR1, &b, NULL); while (1) { sleep(1); if (!block_usr1) { raise(SIGUSR1); } } return 0; }
通过全局标志block_usr1控制主循环是否发送SIGUSR1,同时保留sa_mask确保处理SIGINT的过程中不会被SIGUSR1打断。
方式2:用sigprocmask修改全局信号掩码
#include <stdio.h> #include <unistd.h> #include <signal.h> void handler(int sig) { printf("ctrl c\n"); sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); // 全局阻塞SIGUSR1 sigprocmask(SIG_BLOCK, &mask, NULL); sleep(3); // 解除全局阻塞 sigprocmask(SIG_UNBLOCK, &mask, NULL); } void handler1(int sig) { printf("user sig\n"); } int main() { struct sigaction a; a.sa_handler = &handler; sigemptyset(&a.sa_mask); a.sa_flags = 0; struct sigaction b; b.sa_handler = &handler1; sigemptyset(&b.sa_mask); b.sa_flags = 0; sigaction(SIGINT, &a, NULL); sigaction(SIGUSR1, &b, NULL); while (1) { sleep(1); raise(SIGUSR1); } return 0; }
直接调用sigprocmask修改进程的全局信号掩码,在指定时间段内完全阻塞SIGUSR1,不受信号处理函数执行状态的限制。
验证效果
使用任意一种方式后,按下Ctrl+C会输出"ctrl c",之后的3秒内不会输出"user sig",3秒后恢复正常发送SIGUSR1,符合信号阻塞的预期效果。
内容的提问来源于stack exchange,提问作者user24174052

