【问题标题】:How to avoid scanf after my signal handler function in C?如何在 C 中的信号处理函数之后避免 scanf?
【发布时间】:2015-10-09 14:19:57
【问题描述】:

我有这个代码:

#include <stdio.h>
#include <signal.h>
void signal_handler(int signal) {
    printf("Caught signal in CHILD.\n");
}

int main(void) {
    int s;
    signal(SIGTSTP, signal_handler);
    while(1){
         printf("%s@%s/# ",getlogin(),get_current_dir_name());
         scanf("%d",&s);
    }
    return 0;
}

当我运行它打印的代码时:

something: ^ZCaught signal in CHILD.

据我所知,当我按下 ctr-z 时,scanf 不会执行。虽然在我的函数中的 printf 之后它直接进入 scanf,等待输入然后再次启动循环。当我按 ctr-z 并再次启动 while 循环时,有什么办法可以避免 scanf?我试过类似的东西

void signal_handler(int signal) {
    printf("Caught signal in CHILD.\n");
    printf("%s@%s/# ",getlogin(),get_current_dir_name());
}

但它没有用。在第二个 printf 直接进入 scanf 之后,等待输入,然后再次开始循环。我可以以某种方式重新开始循环吗?

【问题讨论】:

  • 我没有得到你。代码完全按照您编写的方式执行。当您第一次按 ctrl-z scanf 时,会跳过并重新启动循环。
  • 这是我的问题! Scanf 没有跳过!我不明白为什么......
  • 最糟糕的代码可能是将 exit(1) 添加到您的信号处理程序中。我会发布一个例子

标签: c linux signals


【解决方案1】:

信号处理程序正在在 STDIN 的 read 期间中断 scanf。但是,由于您设置信号处置的方式,read 系统调用会在信号处理程序返回后立即重新启动。这就是为什么您“卡在”scanf 而不是回到循环顶部的原因。

您可以做的一件重要的事情是use sigaction rather than signal。这将强制您指定中断呼叫的行为:是否重新启动它们?

接下来要做的是将信号处理程序限制为async-signal-safe 的函数,以免冒misery 的风险。

顺便说一句,要进行的另一项更改是为我们提供所有必需的包含 (&lt;unistd.h&gt;?) 和定义 (_GNU_SOURCE?) 以使您的程序正常运行。

【讨论】:

    【解决方案2】:

    正如评论最糟糕的解决方案应该是:

    #include <stdio.h>
    #include <signal.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    void signal_handler(int signal) {
        printf("Caught signal in CHILD.\n");
        exit(1);
    
    }
    
    int main(void) {
        int s;
        signal(SIGTSTP, signal_handler);
        while(1){
             printf("test\n");
             scanf("%d",&s);
        }
        return 0;
    }
    

    更好的解决方案

    #include <stdio.h>
    #include <signal.h>
    
    static volatile int keepRunning = 1;
    
    void signal_handler(int signal) {
        printf("Caught signal in CHILD.\n");
        keepRunning = 0;
    
    }
    
    int main(void) {
        int s;
        signal(SIGTSTP, signal_handler);
        while(keepRunning){
             printf("test\n");
             scanf("%d",&s);
        }
        return 0;
    }
    

    在 cmets 之后编辑

    #include <stdio.h>
    #include <signal.h>
    
    static volatile int skipPrintf= 1;
    
    void signal_handler(int signal) {
        printf("Caught signal in CHILD.\n");
        skipPrintf= 1;
    
    }
    
    int main(void) {
        int s;
        signal(SIGTSTP, signal_handler);
        while(1){
             if (skipPrintf == 0)
             {
                 printf("test\n");
             }
             else
             {
                 skipPrintf = 0;
             }
             scanf("%d",&s);
        }
        return 0;
    }
    

    【讨论】:

    • 退出程序终止。我想重新开始while循环。我想在按下 ctr-z 后再次打印测试,作为你的例子,然后 scanf 等待输入。逆天!!!我从未见过有人使用易失性!感谢您的帮助
    • 在这种情况下 volatile 是强制性的,因为在 t 处理程序和 main 中修改了 keepRunning。
    • @Csd 我真的不明白你。您发布的代码完全按照您的意愿执行。按 ctrl-z 重做 printf 并转到 scanf。
    • 但我不想去scanf!我想从头开始重新开始while循环。
    • @Csd 是您发布的代码的作用。 printf --> 等待 scanf --> 按 ctrl-z --> 转到信号处理程序---> printf egain-->scanf
    猜你喜欢
    • 2013-03-13
    • 2011-11-28
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 1970-01-01
    • 2020-09-20
    • 2013-12-25
    • 1970-01-01
    相关资源
    最近更新 更多