处理信号后如何停止从键盘读取?

How to stop reading from keyboard once a signal is handled?

我正在编写一个程序,其中 SIGINT 信号在第一次发送时被处理,但之后设置为默认值。所以,例如,我有这个:

static volatile int stop_terminating = 1;

void handler(int dummy) {
    stop_terminating = 0;
}

int main(){
    signal(SIGINT, handler);
    char input[256];
    while(1){
        if(stop_terminating == 0){
            // reset the action of the signal to default
            signal(SIGINT, SIG_DFL);
            printf("Message sent.\n");
            // increment counter so it doesn't enter this condition again
            stop_terminating++;
        }
        printf("User input:\n");
        fgets(input, sizeof(input), stdin);
        // In this stage, I wanna press CTRL+C and print a message, stopping the fgets
        // but what happens is: I press CTRL+C, the signal is catched, but fgets
        // is still asking for an input, and after I send something, the my message is printed
        // because it looped through the while(1) again.
    }
}

如何阻止 fgets 请求输入并只打印消息然后再次请求输入?

当它到达 EOF 时,您从 fgets 得到一个 NULL。从键盘上,通常用 CTRL-D (Linux/Unix/MacOS X) 或 CTRL-Z (DOS/Windows,我认为 MacOS 在 X 之前)

信号的 Linux 手册页说

Interruption of system calls and library functions by signal handlers

If a signal handler is invoked while a system call or library function call is blocked, then either:

  • the call is automatically restarted after the signal handler returns; or

  • the call fails with the error EINTR.

Which of these two behaviors occurs depends on the interface and whether or not the signal handler was established using the SA_RESTART flag (see sigaction(2)).

您可以将 siginterrupt() 函数与 signal() 一起使用,或者使用 sigaction() 而不是 signal() 来注册您的信号处理程序,以禁用重新启动read() 信号后系统调用。

但是请注意,C 库中的 fgets() 可能会多次调用 read() 直到找到换行符,因此您可能还需要切换到使用较低级别的函数而不是 stdio.h API。

如果您关闭标准输入 fgets 将立即 return,然后您可以尝试再次打开标准输入。这很奇怪,但可以作为解决方法