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

问题描述

在大学里,我们目前正在学习守护进程以及如何处理信号。 但是为什么信号处理程序调用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);
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] = '\0';

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

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

解决方法

回答

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

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

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

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


旁边

上面的评论者说得很对:你正在研究的代码是一个糟糕的例子。

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

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

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