如果不查看其余代码,很难判断到底是什么问题,但您显示的代码至少存在一个问题:
在返回之前,sigsuspend(2) 会恢复调用时处于活动状态的信号掩码。如果您在调用sigsuspend(2) 之前没有相应地更改进程的信号掩码,那么在从sigsuspend(2) 返回和测试flag 的值之间有一个时间窗口,可能会传递其他未决信号(或者甚至可能在生成和传递新信号的情况下)。如果这些信号被捕获并且处理程序将flag 的值更改为另一个值,则您“丢失”了SIGUSR2 的处理程序所做的更新。
例如,考虑这个程序:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
volatile sig_atomic_t flag;
void handler1(int signo) {
printf("In handler1\n");
flag = 1;
}
void handler2(int signo) {
printf("In handler2\n");
flag = 2;
}
int main(void) {
struct sigaction sigact;
sigact.sa_handler = handler1;
sigact.sa_flags = 0;
sigfillset(&sigact.sa_mask);
if (sigaction(SIGUSR1, &sigact, NULL) < 0) {
perror("sigaction()");
exit(EXIT_FAILURE);
}
sigact.sa_handler = handler2;
if (sigaction(SIGUSR2, &sigact, NULL) < 0) {
perror("sigaction()");
exit(EXIT_FAILURE);
}
sigset_t mask;
sigfillset(&mask);
sigdelset(&mask, SIGUSR1);
sigsuspend(&mask);
printf("%d\n", flag);
return 0;
}
它捕获SIGUSR1和SIGUSR2,阻塞除SIGUSR1之外的所有信号,然后调用sigsuspend(2)。
运行它,然后发送SIGUSR2,然后发送SIGUSR1。这可确保在看到 SIGUSR1 并对其采取行动之前有一个待处理的信号。它还会导致SIGUSR2 在SIGUSR2 被解除阻塞后立即传递,这发生在sigsuspend(2) 返回之后(因为我们没有触摸进程的信号掩码):
filipe@filipe-Kubuntu:~/dev$ kill -SIGUSR2 29755
filipe@filipe-Kubuntu:~/dev$ kill -SIGUSR1 29755
输出:
filipe@filipe-Kubuntu:~/dev$ ./a.out
In handler1
In handler2
2
你如何解决它?只需确保进程的信号掩码设置为与您在sigsuspend(2) 中使用的掩码相同,这样它就不会错误地恢复掩码。这就像在调用 sigsuspend(2) 之前添加这个一样简单:
if (sigprocmask(SIG_SETMASK, &mask, NULL) < 0) {
perror("sigprocmask()");
exit(EXIT_FAILURE);
}
所以,更新后的程序:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
volatile sig_atomic_t flag;
void handler1(int signo) {
printf("In handler1\n");
flag = 1;
}
void handler2(int signo) {
printf("In handler2\n");
flag = 2;
}
int main(void) {
struct sigaction sigact;
sigact.sa_handler = handler1;
sigact.sa_flags = 0;
sigfillset(&sigact.sa_mask);
if (sigaction(SIGUSR1, &sigact, NULL) < 0) {
perror("sigaction()");
exit(EXIT_FAILURE);
}
sigact.sa_handler = handler2;
if (sigaction(SIGUSR2, &sigact, NULL) < 0) {
perror("sigaction()");
exit(EXIT_FAILURE);
}
sigset_t mask;
sigfillset(&mask);
sigdelset(&mask, SIGUSR1);
if (sigprocmask(SIG_SETMASK, &mask, NULL) < 0) {
perror("sigprocmask()");
exit(EXIT_FAILURE);
}
sigsuspend(&mask);
printf("%d\n", flag);
return 0;
}
这按预期工作:保证在sigsuspend(2) 返回和您测试flag 之后的时间窗口之间不会执行其他信号处理程序。
另一个重要说明:我不知道您是如何设置信号处理程序的,但如果您使用的是signal(2),那么请不要:它的语义是平台相关的,它可能不会像您想要的那样运行。您应该完全按照我在示例程序中显示的那样使用sigaction(2)。需要sigfillset(&sigact.sa_mask) 行来确保当信号处理程序运行时,所有其他信号仍然被阻塞 - 否则,在执行SIGUSR1 的处理程序过程中传递信号可能会调用另一个更改标志的处理程序.