【问题标题】:why is a signal-handler calling signal() in his method-body?为什么信号处理程序在他的方法体中调用 signal()?
【发布时间】:2021-01-06 15:36:02
【问题描述】:

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

在我们的教科书中有这个例子:

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] = '\0';

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

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

【问题讨论】:

  • 有点偏离主题,但我可以肯定地告诉你,最好不要在handlers 中使用标准函数,如果你需要输出消息,请使用write() 而不是printf。至少您将来知道这一点,并且您不会犯与示例中相同的错误。
  • 在我们的教科书中有这个例子: Ooof。一个教科书,它做不安全的事情,比如从信号处理程序调用printf()?!?
  • @real_G 哇,如果你的教授犯了这样的错误,那是有问题的,但无论如何。为您未来的项目记住它。我不确定handler 中的signal,所以让我们看看是否有人准备得更充分。
  • The semantics when using signal to establish a signal handler vary across systems; do not use it for this purpose 无论如何,(在Linux上)它建立了一个一次性处理程序,它必须在触发后重新安装。
  • 您可能不应该在过去十年左右编写的任何代码中使用signal 注册信号处理程序,也许是从 90 年代中期开始。使用sigaction

标签: c signals daemon


【解决方案1】:

回答

代码正在重新安装信号处理程序,以便后续的 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() 怎么办?如果五秒钟的 ALRM 处理程序调用中断了一个 INT 处理程序调用怎么办?

【讨论】:

    猜你喜欢
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多