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

how to alternate continously Signal handler

我想用 c 语言为 linux 编写一个程序,它捕获第一个 SIGUSR1 信号,忽略第二个信号并继续这种行为(捕获-忽略)连续的 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;
}

你没有。

您可以做的是让您的信号处理程序决定是否做某事——例如,是否调用另一个函数。然而,这并不完全可靠,因为 standard POSIX signalsSIGUSR1 没有排队。如果在(几乎)同时发送两个或多个信号,则实际上只有一个信号被传送。 POSIX 实时信号(SIGRTMIN+0SIGRTMAX-0 -- 从程序员的角度来看,只有数量和语义不同)被排队,但在某些情况下甚至可以丢弃它们。

在所有情况下,请记住信号处理函数只能使用 async-signal safe functions. If you need to be able to use all functions, you should instead block the signals in all threads, and have a dedicated thread receive the signals using e.g. sigwaitinfo()。在这种情况下,您没有信号处理函数,而是一个 接收 信号的专用线程,因此可以自由使用它想要的任何函数。

如果我们将问题改写为 "How do I alternate the handling of a delivered signal in a single-threaded program?",答案很简单:您使用 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_flags.

中使用 sigaction() 而没有 SA_SIGINFO 安装信号处理程序

POSIX 标准说你最多可以做 128 种情况(因为 sig_atomic_t 保证能够表示值 0127,包括在内)这个方式。

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

在多线程程序中,必须依赖编译器提供的原子操作,或者遗留的 __sync built-ins, or __atomic 内置函数。它们不是 GCC 特定的;至少 Intel Compiler Collection 和 clang 也提供了它们。为了在两个选项之间交替,our = __atomic_xor_fetch(&counter, 1, __ATOMIC_SEQ_CST);our = __sync_xor_and_fetch(&counter, 1); 可用于自动获取计数器并在 0 和 1 之间翻转。对于非二次幂的选项,通常使用比较和交换循环。