由于SIGINT

时间:2019-09-04 07:07:49

标签: c signals posix

我有一个write_full,即使该缓冲区被信号中断,该缓冲区也应将缓冲区完全写入标准输出。
我有一个循环,它将write_full保留为一个字符串,直到quit被信号处理程序更改为止。这是代码:

#include <signal.h>
#include <unistd.h>
#include <errno.h>

volatile sig_atomic_t quit = 0;

void sigint_handler(int s)
{
    quit = 1;
}

int write_full(char *buf, size_t len)
{
    while (len > 0) {
        ssize_t written = write(STDOUT_FILENO, buf, len);
        if (written == -1) {
            if (errno == EINTR) { 
                continue; 
            }
            return -1;
        }
        buf += written;
        len -= (size_t)written;
    }
    return 0;
}

int main(void)
{
    struct sigaction act = {
        .sa_handler = sigint_handler
    };
    sigaction(SIGINT, &act, NULL);

    while (!quit) {
        write_full("loop\n", 5);
    }

    write_full("cleanup", 7);

    return 0;
}

我希望程序在打印“清理”之前完全编写“循环”,但是我看到这样的输出:

  

循环
    循环
    循环
    l ^ C
    清理

为什么会这样?我希望它是这样的:

  

循环
    循环
    循环
    l ^ Coop
    清理

因为write_full应该继续写“ oop \ n”部分,即使在第一次写是由于中断而作的短写之后。我在信号处理程序上设置了一个断点,然后踩了一步,看来write报道说它已经写了4个字符,即使它只向标准输出中写了“ l”。因此,它接下来只写“ \ n”,而不是写“ oop \ n”。

l^C
Program received signal SIGINT, Interrupt.

Breakpoint 1, sigint_handler (s=2) at src/main.c:9
9           quit = 1;
(gdb) next
10      }
(gdb) next
write_full (buf=0x4020a0 "loop\n", len=5) at src/main.c:16
16              if (written == -1) {
(gdb) print written
$1 = 4

为什么会这样?我该如何解决呢?

1 个答案:

答案 0 :(得分:2)

Ctrl-C弄乱了终端输出。程序将写所有应写的内容,但是默认情况下,终端驱动程序在Ctrl-C之后剪切行。这不受您程序的控制。如果驱动程序在将 complete 行缓冲区复制到物理设备的过程中看到Ctrl-C,则会发生剪切。输入行缓冲区也将被丢弃。这也与其他产生信号的字符有关。

stty(1)termios(3)手册页中对此进行了简要介绍。

可以使用stty noflsh命令禁用此行为。

您还可以重定向到文件以查看完整的输出。