C 重新注册信号处理程序会导致无限循环

C 重新注册信号处理程序会导致无限循环,c,signals,posix,infinite-loop,sigint,C,Signals,Posix,Infinite Loop,Sigint,对于以下信号处理程序,按Ctrl-C会导致重复调用处理程序,我不知道为什么: (警告:如果键入Ctrl-C,则必须使用kill退出程序) 所以我知道我对信号处理程序有些不了解。我假设只有SIGCONT会到达最后一行,因为SIGINT(例如),当它以默认行为(SIG_DFL)引发时,应该退出而不返回 我还知道,我可以将最后一行封装在一个if语句中,该语句只对SIGCONT执行,但我真的想知道为什么它的行为不符合我的预期 问题: 为什么在无限循环中调用信号处理程序 我如何让一个处理程序做一些有趣的事

对于以下信号处理程序,按Ctrl-C会导致重复调用处理程序,我不知道为什么:

(警告:如果键入
Ctrl-C
,则必须使用
kill
退出程序)

所以我知道我对信号处理程序有些不了解。我假设只有
SIGCONT
会到达最后一行,因为
SIGINT
(例如),当它以默认行为(
SIG_DFL
)引发时,应该退出而不返回

我还知道,我可以将最后一行封装在一个if语句中,该语句只对
SIGCONT
执行,但我真的想知道为什么它的行为不符合我的预期

问题:
  • 为什么在无限循环中调用信号处理程序
  • 我如何让一个处理程序做一些有趣的事情,调用默认行为,然后在默认行为没有退出程序的情况下重新注册自己
  • MCVE 这可以通过将其写入文件
    sigtest.c
    并执行
    make sigtest
    来运行。使用
    Ctrl-C
    提升
    SIGINT
    ,在另一个终端中,准备执行
    ps | grep sigtest
    ,然后执行
    kill

    #包括
    #包括
    #包括
    #包括
    静态无效处理程序(int sig){
    //做些有趣的事
    //这样我就能知道我是否在一个无限循环中
    写(1,“A”,1);
    //提高正常的信号行为
    //这确保了正常的信号行为
    //例如,如果使用Ctrl-C,则以代码130退出
    信号(sig,sig_DFL);
    提高(sig);
    //重新注册处理程序
    //这样,如果信号没有退出程序和信号
    //如果以后再次发送,则此处理程序将再次运行
    信号(信号发生器,处理器);
    }
    内部主(空){
    字符c;
    信号(SIGINT,handler);
    信号(SIGTSTP,处理器);
    信号(SIGCONT,处理器);
    printf(“键入“x”和“回车”退出\n”);
    而(1){
    c=getchar();
    printf(“获取字符:%c\n”,c);
    如果(c='x'){break;}
    }
    }
    
    我屏蔽了,忘记了信号在处理时被屏蔽。这意味着在处理程序返回之前,
    SIGINT
    实际上不会被引发,并且在我将操作从
    SIG\u DFL
    设置回我的自定义处理程序之后。因此,它是循环的

    我的示例的工作处理程序如下所示:

    static void handler(int sig) {
            if (sig == SIGCONT) {
                    // do something interesting
                    signal(sig, handler);
                    signal(SIGTSTP, handler);
            } else {
                    // do something else interesting
                    signal(sig, SIG_DFL);
                    raise(sig);
            }
    }
    

    呃,我忘了:正在处理的信号在处理时被阻止,因此在我的处理程序返回后才调用
    raise
    ,默认行为由最后一行对所有内容启用…
    signal()
    ,不建议使用,
    man signal
    :“避免使用它:改用sigaction(2)”@cdarke我认为
    sigaction
    处理程序也会阻止他们正在处理的信号,因此我认为这与问题无关。但是我同意你的看法。@GregSchmit No与
    信号
    ,传递的信号没有被阻止(至少没有指定),这是你应该使用
    sigaction
    的原因之一。我觉得这很奇怪。为什么要在SIG处理程序中间更改SIG处理程序?您没有跟踪上一个处理程序的值是什么,因此对于您拥有的任何实现,您似乎都脱离了脚本。其思想是参与一些操作,然后继续执行信号处理程序的默认行为
    SIGCONT
    SIGTSTP
    是特殊情况,因为它们可能会被多次调用,因为它们不会导致程序退出。@jwdonahue最初的问题是一个更改
    termios
    设置的软件。如果有人点击了
    Ctrl-C
    ,我想恢复
    termios
    的更改,但随后继续正常的信号行为(如使用代码130退出)。但后来我遇到了一些问题,有人按了
    Ctrl-Z
    ,然后又按了
    fg
    。要处理这个问题,我必须确保在
    SIGCONT
    上重新注册我的信号处理程序,否则如果他们注册两次,那么
    termios
    设置就会关闭。@jwdonahue谢谢!是的,我的问题是在
    Ctrl-Z
    fg
    (分别是signals
    SIGTSTP
    SIGCONT
    )的情况下必须重新注册处理程序,否则事情只会在第一次运行。所以听起来你真的需要两个信号处理程序,每种类型一个。但我认为你应该约束你的管理者。某些地方的静态模块初始化可能也有自己的信号处理程序。
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    static void handler(int sig) {
            // do something interesting
    
            // write so I can see if I'm in an infinite loop
            write(1, "A", 1);
    
            // raise normal signal behavior
            // this ensures normal signal behavior
            // for example, exiting with code 130 if Ctrl-C is used
            signal(sig, SIG_DFL);
            raise(sig);
    
            // re-register handler
            // that way, if signal doesn't exit the program and the signal
            //   is sent again in the future, this handler will run again
            signal(sig, handler);
    }
    
    int main(void) {
            char c;
            signal(SIGINT, handler);
            signal(SIGTSTP, handler);
            signal(SIGCONT, handler);
            printf("type 'x' and 'Enter' to exit\n");
            while (1) {
                    c = getchar();
                    printf("got char: %c\n", c);
                    if (c == 'x') { break; }
            }
    }
    
    static void handler(int sig) {
            if (sig == SIGCONT) {
                    // do something interesting
                    signal(sig, handler);
                    signal(SIGTSTP, handler);
            } else {
                    // do something else interesting
                    signal(sig, SIG_DFL);
                    raise(sig);
            }
    }