2015-06-26 82 views
0
sigfillset(&set); 
sigdelset(&set, SIGUSR2); 

sigsuspend(&set); 

// signal handler sets a flag 

if(flag == 1) 
    //do something 

在这种情况下,我的线程只在SIGUSR2交付时才会唤醒。 然而,似乎还有其他东西迫使sigsuspend返回,但我不知道什么,因为所有其他信号被屏蔽。 这个代码片段有什么问题吗?Sigsuspend系统调用问题

非常感谢您

+0

请向我们展示一个[MCVE](http://stackoverflow.com/help/mcve)。 – pilcrow

回答

0

这是很难说究竟是什么错误没有看到代码的其余部分,但至少有一个问题,你的代码显示:

之前返回,sigsuspend(2)恢复被调用时处于活动状态的信号掩码。如果您在调用sigsuspend(2)之前没有相应地更改过程的信号模板,则在从sigsuspend(2)返回并测试其他未决信号可能被传送的值之间存在一段时间窗口(或者甚至可能是新信号生成并交付)。如果捕获到这些信号并且处理程序将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)收益恰好(因为我们没有接触过程中的信号掩码):

[email protected]:~/dev$ kill -SIGUSR2 29755 
[email protected]:~/dev$ kill -SIGUSR1 29755 

输出:

[email protected]:~/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的处理程序过程中传送信号可能会调用另一个更改标志的处理程序。