gpt4 book ai didi

c - SigSuspend系统调用问题

转载 作者:行者123 更新时间:2023-11-30 17:13:05 25 4
gpt4 key购买 nike

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;
}

它捕获 SIGUSR1SIGUSR2 ,阻止除 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com