SIGQUIT 和 STDIN(读取函数的意外转储)

SIGQUIT and STDIN (unexpected dump of read function)

我在处理 stdin 和 sigquit 信号时遇到了问题。任务是忽略 sigquit 信号。一切都很好,除了所有 'read' 缓冲区都消失了,我不知道如何避免它。这是我的代码:

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <strings.h>

int main(void)
{
    char buffer[4096];
    int byte;

    bzero(buffer, 4096);
    signal(SIGQUIT, SIG_IGN);
    while ((byte = read(0, &buffer, 4096)))
    {
        if (strlen(buffer) == 5 && !strncmp(buffer, "exit", 4))
            break ;
        write(1, "STDOUT | ", strlen("STDOUT | "));
        write(1, buffer, strlen(buffer));
        bzero(buffer, 4096);
    }
    write(1, "Program is finished\n", strlen("Program is finished\n"));
    return (0);
}

这是我的输出:

$ ./test
hello world
STDOUT | hello world
hello world^\
STDOUT |
The way it should be
STDOUT | The way it should be
And how it is now^\
STDOUT |
i need help
STDOUT | i need help
really^\
STDOUT |
exit
Program is finished

OS:MacOS 莫哈韦沙漠 - 10.14.6 Clang 版本:11.0.1

这不是您的代码中的错误。您正确地忽略了 SIGQUIT,并且您的读写循环大部分都很好(我看到的唯一实际 bug 是您正在分配 return 值 read 到错误类型的变量,然后没有给予足够的重视;但这不是你眼前问题的原因)。

发生的事情是,当您键入 ^\ 时,tty 驱动程序会生成一个 SIGQUIT 并且还会丢弃任何未决的输入行 .此行为由 POSIX 指定,但只是暗示:NOFLSH 本地模式标志的定义读取

If NOFLSH is set, the normal flush of the input and output queues associated with the INTR, QUIT, and SUSP characters shall not be done.

(开放组基础规范第 7 期,2018 年版,§11.2.5 Local Modes。)

因此,如果 NOFLSH 未设置,这是默认设置,那么在处理 ^ 时,输入和输出队列都将被刷新(内容被丢弃) C^\^Z.

您可以使用 tcsetattr 设置 NOFLSH 标志,但您必须注意在退出时再次取消设置。我建议使用 readline or curses 库,而不是尝试自己处理低级 tty API。

当您点击 ^C (intr)、^Z (susp) 和 ^\ (quit) 时,您的 tty 层正在刷新您的输入。

解决方案是在 运行 你的程序之前调用 stty noflsh

如果您需要以编程方式执行此操作,请参阅此 termios manual page

中的 NOFLSH 标志