如何连续交替信号处理程序

时间:2016-09-10 14:48:50

标签: c linux signals handler

我想用c编写一个用于linux的程序来捕获第一个SIGUSR1信号,忽略第二个信号并继续这种行为(catch-ignore)以获取连续的SIGUSR1信号。

我想知道如何在两个处理程序之间保持交替,因为一旦我将处理程序设置为SIG_IGN,信号将被忽略,我将无法检测到它并采取相应的行动。

这是我尝试过的代码:

int tst;
void sigusr1_handler(){
   if(tst==0){
      signal(SIGUSR1,SIG_IGN);
      tst=1;
    } 
   else tst= 0;
}


int main(){
   signal(SIGUSR1, sigusr1_handler);
   tst=1;
   while(1){}
return 0;
}

1 个答案:

答案 0 :(得分:1)

你没有。

你可以做的是让你的信号处理者决定是否做某事 - 例如,是否要调用另一个功能。但是,这并不完全可靠,因为像SIGUSR1这样的standard POSIX signals没有排队。如果在(几乎)同时发送两个或更多信号,则实际仅传送一个。 POSIX实时信号(SIGRTMIN+0SIGRTMAX-0 - 从程序员的角度来看,只有数字和语义不同)排队,但即使它们在某些情况下也可以删除。

在所有情况下,请记住信号处理函数只能使用async-signal safe functions。如果您需要能够使用所有功能,则应该阻止所有线程中的信号,并使专用线程使用例如线程接收信号。 sigwaitinfo()。在这种情况下,你没有信号处理函数,而是一个接收信号的专用线程,因此可以自由使用它想要的任何函数。

如果我们将问题改为"如何在单线程程序中交替处理传递的信号?" ,答案很简单:你使用的是volatile sig_atomic_t反击。

对于两个选项之间的交替,do_something_odd()首先:

#include <signal.h>

void my_signal_handler(int signum)
{
    static volatile sig_atomic_t  count = 0;

    switch (++count) {

    case 1:
        do_something_odd();
        break;

    default:
        count = 0;
        do_something_even();
        break;
    }
}

对于三种情况之间的交替,您可以根据需要添加更多case语句:

#include <signal.h>

void my_signal_handler(int signum)
{
    static volatile sig_atomic_t  count = 0;

    switch (++count) {

    case 2:
        do_something_2_of_3();
        break;

    case 1:
        do_something_1_of_3();
        break;

    default:
        count = 0;
        do_something_3_of_3()           
        break;
    }
}

以上假设您使用SA_SIGINFO中没有.sa_flags的{​​{3}}安装信号处理程序。

POSIX标准表示您最多可以处理128个案例(因为sig_atomic_t可以保证能够以这种方式表示0127的值,包括在内。

您可以使用unsigned intunsigned long执行更大的集合,但是SA_NODEFER中不能有.sa_flags,并且如果相同的处理程序用于多个信号,.sa_mask必须具有由同一处理程序集处理的所有其他信号。这可以确保信号处理程序不会被传递给同一个处理程序的另一个信号中断,并允许我们使用非原子计数器变量。

在多线程程序中,必须依赖于编译器提供的原子操作,即遗留sigaction()内置函数或__sync内置函数。它们不是GCC特有的;至少英特尔编译器集合和clang也提供它们。对于两个选项之间的交替,可以使用our = __atomic_xor_fetch(&counter, 1, __ATOMIC_SEQ_CST);our = __sync_xor_and_fetch(&counter, 1);来原子地获取和翻转0到1之间的计数器。对于非幂的两个选项,通常使用比较和交换循环。