2

我正在使用 C 语言工作。我试图捕捉和处理两个不同的信号:

  • INT:当捕捉到这个信号时,触发action1action2
  • QUIT:当这个信号被捕获时,INT信号动作被切换(action1 -> action2 or action2 -> action1

默认 INT 信号操作设置为action1

在我的代码中,switchaction函数由 QUIT 信号很好地触发,但对 INT 信号操作没有影响:s

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

typedef void (*sighandler_t)(int);
sighandler_t prev_handler;

void action1(int n){
  printf("First message\n");
}
void action2(int n){
  printf("Second message\n");
}

void switchaction(int n){
  printf("Switch action\n");
  prev_handler=action2;
}

int main() {
  prev_handler = action1;
  printf("PID: %d\n", getpid());
  prev_handler= signal(SIGINT,prev_handler);
  signal(SIGQUIT,switchaction);

  travail(); //This function never ends
}

你知道我的代码有什么问题吗?

谢谢,

4

1 回答 1

2

你的系统调用

prev_handler= signal(SIGINT,prev_handler);

prev_handler正在执行signal系统调用时将信号处理程序设置为变量的值。更改(之后)的值prev_handler不会更改SIGINT信号的处理。换句话说,signal(和大多数 C 调用)具有按值语义调用。如果您调用signal一次,内核会保留相同的处理程序(直到您signal使用相同的信号编号再次调用,或者直到您调用sigaction(2)等...)。

仔细阅读(假设您使用的是 Linux)signal(7)signal(2)手册页。

我会改为定义

volatile sig_atomic_t howhandle;

void switchaction(int n __attribute__((unused))) {
    if (howhandle) 
       howhandle = 0;
    else 
       howhandle = 1;
}

void handleint (int n) {
    if (howhandle) action1(n); else action2(n);
}

并安装

signal(SIGINT, handleint);
signal(SIGQUIT, switchaction);

另外,请注意在处理程序内部调用printf是不正确的(因为printf不是异步信号安全函数,但您调用它 in action1,由handleint... 调用)。再读信号(7)

您应该有一些其他volatile sig_atomic_t变量并在您的工作函数内的适当位置进行测试(并清除它们)travail,但仅在您的信号处理程序中设置它们。设置volatile sig_atomic_t变量几乎是您在信号处理程序中唯一可以可靠地做的事情。

如果您接受 Linux 特定的解决方案,请了解有关signalfd(2)的更多信息(并使用poll(2) ...)。另请阅读高级 Linux 编程

于 2013-11-11T18:05:09.933 回答