【问题标题】:Questions about catching Unix signals关于捕获 Unix 信号的问题
【发布时间】:2011-09-02 18:22:51
【问题描述】:

以下代码仅捕获一次“SIGINT”信号然后中断(程序存在):

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

void IntHandler(int value);

void CatchIntSignal()
{
    struct sigaction intAction;
    intAction.sa_handler = IntHandler;
    sigemptyset(&intAction.sa_mask);
    intAction.sa_flags = 0;
    //if to uncomment any of "0" or "SIG_IGN" - IntHandler will be never called:
    //intAction.sa_sigaction = 0/*SIG_IGN*/;
    if(sigaction(SIGINT, &intAction, NULL) != 0)
    {
        printf("sigaction() failed.\n");
    }
}

void IntHandler(int value)
{
    printf("IntHandler(%d)\n", value);
    //uncommenting this does not help:
    //CatchIntSignal();
}

int main()
{
    CatchIntSignal();
    getchar();
    return 0;
}

我必须如何修改此代码以在 SIGINT 捕获后保留程序的退出? 如果将 intAction.sa_sigaction 设置为 0 或 SIG_IGN - IntHandler 将永远不会被调用 - 但为什么呢?哪个未定义的值必须说系统“有必要调用 IntHandler”?如果我将一些处理程序设置为 intAction.sa_sigaction - 这个处理程序将被调用(但 IntHandler 不会)。系统如何知道我确实为 intAction.sa_sigaction 设置了一些东西?

【问题讨论】:

  • 我不明白你想让你的程序做什么。是不是:第一次收到SIGINT,调用IntHandler,然后程序退出?或者是:每次收到SIGINT,都会调用IntHandler;在 getchar() 返回之前程序不会退出?
  • 我希望我的程序能够捕获 SIGINT 信号并且不会在它之后退出。这样在每个“Ctrl+C”程序之后都会打印“IntHandler(2)”并继续工作。

标签: unix signals


【解决方案1】:

在捕获中断信号并在捕获代码中处理后,您需要将处理设置回SIG_DFL

编辑:请忽略。这仅适用于旧的 unix signal()。

【讨论】:

  • 不适用于sigaction();这是sigaction() 优于signal() 的主要优势。如果使用了signal(),你会更接近正确。处理程序将自动重置为 SIG_DFL,并且有必要在处理程序中重置处理程序。
【解决方案2】:

您的问题是struct sigactionsa_handlersa_sigaction 字段实际上是同一个字段。引用 sigaction(2) 的 (OSX) 手册页:

 struct  sigaction {
         union __sigaction_u __sigaction_u;  /* signal handler */
         sigset_t sa_mask;               /* signal mask to apply */
         int     sa_flags;               /* see signal options below */
 };

 union __sigaction_u {
         void    (*__sa_handler)(int);
         void    (*__sa_sigaction)(int, struct __siginfo *,
                        void *);
 };

 #define sa_handler      __sigaction_u.__sa_handler
 #define sa_sigaction    __sigaction_u.__sa_sigaction

因此,您对sa_sigaction 的分配将覆盖您已经设置的处理程序。您应该只设置sa_handler 并单独留下sa_sigactionCatchIntSignal 应该这样读:

void CatchIntSignal()
{
    struct sigaction intAction;
    intAction.sa_handler = IntHandler;
    sigemptyset(&intAction.sa_mask);
    intAction.sa_flags = SA_RESTART;
    if(sigaction(SIGINT, &intAction, NULL) != 0)
        printf("sigaction() failed: %s\n", strerror(errno));
}

(您可能需要添加string.herrno.h 的#includes 才能编译strerror(errno) 位。始终在系统调用失败时触发的错误消息中包含strerror(errno)。)

(更正:在每个 ninjalj 的标志中添加了 SA_RESTART。)

【讨论】:

  • Union...你为我揭示了真相。谢谢!
【解决方案3】:

您的问题可能是系统调用被中断,所以getchar() 返回,可能是EOF。程序接下来要做的就是退出......

因此,您可以尝试检查getchar() 返回的内容,重置stdin 上的错误状态,然后再次调用getchar() 以获取下一个信号。

【讨论】:

  • 所以 OP 应该要么在 sa_flags 上设置 SA_RESTART,要么在 getchar() 失败时检查 EINTR
  • 是的,确实如此。谢谢。
  • 哎呀!我应该记得SA_RESTART。感谢您指出ninjalj。
  • @Zack,@ninjali - 我也应该记得 SA_RESTART。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
相关资源
最近更新 更多