sigfillset(&set);
sigdelset(&set, SIGUSR2);
sigsuspend(&set);
// signal handler sets a flag
if(flag == 1)
//do something
在这种情况下,我的线程仅在传送SIGUSR2时唤醒。 然而,似乎有其他东西迫使sigsuspend返回,但我不知道是什么,因为所有其他信号被掩盖。 这个代码片段有什么问题吗?
非常感谢
答案 0 :(得分:0)
如果没有看到剩下的代码,很难说出究竟是什么问题,但是您显示的代码至少存在一个问题:
在返回之前,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
的处理程序中传递信号可能会调用另一个处理程序这改变了旗帜。