为什么信号处理程序在他的方法体中调用 signal()?

why is a signal-handler calling signal() in his method-body?

在大学里,我们目前正在学习守护进程以及如何处理信号。 但为什么信号处理程序调用 signal()?在主方法中 signal(...) 已经被调用。因此,根据我的理解,当 pkill -SIGUSR1 例如被发送到线程时,主方法中的一个 signal(...) 调用应该足以捕获并委托给处理程序。也许有人可以解释一下。

我们课本上有这个例子:

void sighandler (int sig) {
printf ("Caught signal %d\n", sig);
signal (SIGINT, sighandler);
signal (SIGALRM, sighandler);
}

int main (int argc, char *argv [], char *envp []) {

char buffer [1024];
int len;
signal (SIGINT, sighandler);
signal (SIGALRM, sighandler);
alarm (5);

for (len = 0; len < 10; len++)
 printf ("Counting %d...\n", len), sleep (1);

alarm (10);

while (1) {

 len = read (0, buffer, sizeof (buffer) - 1);

 if (len == -1) {
  perror ("read () failed");
  continue;
  }

 if (len == 0) {
  printf ("Exiting\n");
  exit (0);
  }

 buffer [len] = '[=10=]';

 if (!strncmp (buffer, "exit", 4))
  exit (0);

 write (1, buffer, strlen (buffer));
  }
}

回答

代码正在重新安装信号处理程序,以便后续的 SIGINT 和 SIGALRM 再次调用相同的信号处理程序。

为什么?从历史上看,signal() 的某些实现会在调用用户定义的信号处理程序时将信号处理重置为默认值 (SIG_DFL),有效地使信号处理程序成为“一枪”事件。有些人没有这样做。

因此,一种常见的做法是让用户定义的信号处理程序自行重新安装,以使处理程序有效地永久存在。 (在没有重置处置的系统上,这只会通过引入无意义的系统调用使信号处理程序的效率稍微降低。)

sigaction()successor to signal() which was standardized in POSIX.1-1988 通过提供标志 SA_RESETHAND 来控制是否重置处理程序来解决此歧义。


一边

楼上的评论说的很对:你学习的代码是一个不好的例子。

任何对 signal() 的使用在现代的生产质量代码中都是可疑的。仅此一项就无法通过许多商店的代码审查。

即使允许 signal(),在 printf() 之前 没有立即 重新安装处理程序这一事实也有点奇怪。

printf() 不是 async-signal-safe。在非常简单的玩具程序中,它可以在信号处理程序中毫无问题地使用,但即使是这个例子 也不安全 。如果在主循环的 printf() 期间调用处理程序中的 printf() 怎么办?如果那五秒钟的 ALRM 处理程序调用中断了 INT 处理程序调用怎么办?