sigfillset(&set);
sigdelset(&set, SIGUSR2);
sigsuspend(&set);
// signal handler sets a flag
if(flag == 1)
//do something
在这种情况下,仅当传递SIGUSR2时,我的线程才会唤醒。
但是,似乎还有其他一些因素迫使sigsuspend返回,但是我不知道是什么,因为所有其他信号都被屏蔽了。
此代码段中有任何问题吗?
非常感谢你
最佳答案
在不看其余代码的情况下很难分辨出什么是错误的,但是您显示的代码至少存在一个问题:
返回之前,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
的处理程序期间传递信号可能会调用另一个更改标志的处理程序。关于c - Sigsuspend系统调用问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31079483/