3

我有一个用 C 编写的小应用程序,旨在在 Linux 上运行。该应用程序的一部分接受来自键盘的用户输入,并且它使用非规范终端模式,以便它可以响应每个击键。

接受输入的代码部分是一个在循环中重复调用的简单函数:

char get_input()
{
    char c = 0;
    int res = read(input_terminal, &c, 1);
    if (res == 0) return 0;
    if (res == -1) { /* snip error handling */ }
    return c;
}

这会从终端读取单个字符。如果在某个时间范围内(由 termios 结构中的 c_cc[VTIME] 值指定)没有接收到输入,则 read() 返回 0,并再次调用 get_input()。

这一切都很好,除了我最近发现如果你在终端窗口中运行这个应用程序,然后关闭终端窗口而不终止应用程序,应用程序不会退出而是启动到 CPU 密集型无限循环,其中 read() 连续无需等待即可返回 0。

那么,如果应用程序从终端窗口运行,然后关闭终端窗口,我怎样才能让应用程序正常退出呢?问题是 read() 永远不会返回 -1,因此错误情况与 read() 返回 0 的正常情况无法区分。所以我看到的唯一解决方案是放入一个计时器,并假设如果出现错误情况read 返回 0 的速度比 c_cc[V_TIME] 中指定的时间快。但是这个解决方案充其量似乎很老套,我希望有更好的方法来处理这种情况。

有什么想法或建议吗?

4

3 回答 3

1

您应该使用 select 而不是终端设置来处理超时。如果终端配置为没有超时,那么它在读取时将永远不会返回 0,除非在 EOF 上。

Select 为您提供超时,而 read 在关闭时为您提供 0。

rc = select(...);
if(rc > 0) {
        char c = 0;
        int res = read(input_terminal, &c, 1);
        if (res == 0) {/* EOF detected, close your app ?*/}
        if (res == -1) { /* snip error handling */ }
        return c;
} else if (rc == 0) {
   /* timeout */
   return 0;
} else {
   /* handle select error */
}
于 2009-09-03T08:55:13.760 回答
1

您是否在程序退出之前捕获信号并重置事物?我认为 SIGHUP 是你需要关注的一个。可能在信号处理程序中设置一个开关,如果从 read() 返回时开关打开,则清理并退出。

于 2009-07-26T16:47:40.703 回答
0

读取应该在 EOF 上返回 0。即它不会成功读取任何内容。在这种情况下,您的函数将返回 0!

您应该做的是将读取返回的值与 1 和处理异常进行比较。即你要了一个,但你得到了一个吗?

如果返回 -1,您可能需要处理 errno==EINTR。

字符 get_input()
{
        字符 c = 0;
        int res = read(input_terminal, &c, 1);
        开关(水){
        情况1:
                返回 c;
        案例0:
                /* EOF */
        情况1:
                /* 错误 */
        }
}
于 2009-09-03T08:26:43.080 回答