【问题标题】:Unix - Control C and Control Z signal pick up issuesUnix - Control C 和 Ctrl Z 信号拾取问题
【发布时间】:2015-02-11 06:31:19
【问题描述】:

我正在试验 Unix 中提供的信号。我目前关注的两个是 Ctrl+CCtrl+Z。我想捕捉信号,并在屏幕上显示一条消息。我得到了大部分工作。就像按下任一信号时显示的消息一样。然而,它似乎只工作一次。我希望每次按下 Ctrl+CCtrl+Z 时都显示消息。像一个循环。

#include <stdio.h>
#include <signal.h>

void handler (int signal);

int main ()
{
  if (signal(SIGINT, handler) == SIG_ERR)
  {
    write (2, "Error catching signal C \n",26);
  } 
  if (signal(SIGTSTP, handler) == SIG_ERR)
  {
    write(2, "Error catching signal Z \n", 26);
  }
  pause();
}

void handler (int signal)
{
  if (signal == SIGINT)
  {
    write(1, "CONTROLC \n", 11);
  }
  else if (signal == SIGTSTP)
  {
    write(1, "CONTROLZ \n", 11);
  }
  else
  {
    write(2, "error \n", 8);
  }
  main();
}

我试图使用 main 函数,以便它会再次重新启动程序,但我假设它从信号中调用 main,所以它的行为不同?

【问题讨论】:

    标签: c unix signals


    【解决方案1】:

    哇,不要那样做。 :)

    这里发生的情况是,例如,SIGINT 在处理程序执行期间被屏蔽(阻塞)。因此,从处理程序中重新调用 main 会重新运行 main 并阻止 SIGINT。因此,您会看到您的处理程序每​​个信号只触发一次 - 它一直被阻止。 (请注意,signal 不保证这种阻塞行为,这是您should use sigaction instead 的原因之一。)

    典型的信号处理程序应该做尽可能少的工作,只使用async-signal-safe 函数,如果有的话。将处理程序视为对流程的普通流程的中断,这是一个特殊的异步流程,如果需要可以use its own stack

    如果您希望程序表现得像循环,请将其编码为循环:

    static volatile sig_atomic_t flag_int;
    static volatile sig_atomic_t flag_tstp;
    
    static void handle_int(int s)  { flag_int  = 1; }  /* register me with sigaction */
    static void handle_tstp(int s) { flag_tstp = 1; }  /* me, too                    */
    
    ...
      while (1) {
        pause();
        if (flag_int)  { printf("CONTROL C\n"); flag_int  = 0; }
        if (flag_tstp) { printf("CONTROL Z\n"); flag_tstp = 0; }
      }
    

    【讨论】:

    • 我设法通过删除暂停并使用 while(1) 使其工作。不过你的方法似乎更好!
    【解决方案2】:

    不要从您的信号处理程序调用 main(),因为您的程序现在卡在信号处理程序中,并且在处理程序运行时它不会再次为同一信号调用另一个信号处理程序。 (不过,如果您使用 sigaction() 而不是 signal(),则可以更改该行为。

    还可以查看 pause() 调用的作用。

    描述 pause() 导致调用进程(或线程)休眠,直到发出终止进程或导致 调用信号捕获函数。

    所以,你的 pause();呼叫等待直到信号被传递,然后继续您的程序。

    所以,例如这是为了让您的程序保持运行。

    for(;;) {
      pause();
    }
    

    【讨论】:

      【解决方案3】:

      请勿使用信号(2),除非可能将给定信号的处置设置为SIG_DFLSIG_IGN。它的行为因不同的 Unix 而异。

      为了可移植性(在 POSIX 系统中)和更好的控制,您应该通过 sigaction(2) 系统调用安装用户信号处理程序。除此之外,它还允许您在安装处理程序时在一次性模式和持久模式之间进行选择。

      如果您有义务使用 signal(2),那么最好的办法是让处理程序做的最后一件事是重新安装自己作为给定信号的处理程序(实际上这是你想要什么)。

      【讨论】:

      • 很好的指导,但没有解释他看到的行为。历史行为在这里不起作用:在第二个 SIGINT 的情况下,重置为 SIG_DFL 会杀死他的进程。
      • 你是对的,@pilcrow。我完全忽略了处理程序末尾的main() 调用(我猜这很奇怪,以至于我的大脑拒绝了它),并且我没有停下来考虑SIGINT 的默认处理。我删除了不正确的断言。
      猜你喜欢
      • 1970-01-01
      • 2014-11-04
      • 1970-01-01
      • 2016-01-08
      • 1970-01-01
      • 1970-01-01
      • 2017-05-04
      • 1970-01-01
      相关资源
      最近更新 更多