我有一个用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密集型无限循环,其中读取()不等待地连续返回0。
那么,如果从终端窗口运行app,然后终端窗口关闭,我怎样才能正常退出app?问题是read()永远不会返回-1,因此错误条件与read()返回0的正常情况无法区分。所以我看到的唯一解决方案是放入一个计时器,并假设存在错误条件read返回0比c_cc [V_TIME]中指定的时间快。但这个解决方案充其量只是hacky,我希望有更好的方法来处理这种情况。
有任何想法或建议吗?
答案 0 :(得分:1)
您是否在程序退出前捕获信号并重置内容?我认为SIGHUP是你需要关注的。如果在从read()清理并退出时返回开关,则可能在信号处理程序中设置一个开关。
答案 1 :(得分:1)
您应该使用select而不是终端设置来处理超时。如果终端配置没有超时,那么除了EOF之外,它永远不会在读取时返回0。
选择为您提供超时,而读取会在关闭时为您提供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 */
}
答案 2 :(得分:0)
读取应该在EOF上返回0。即它不会成功读取任何内容。 在这种情况下,你的函数将返回0!
您应该做的是将read返回的值与1进行比较并处理异常。 即你问过一个,但你有一个吗?
如果返回-1,您可能想要处理errno == EINTR。
char get_input() { char c = 0; int res = read(input_terminal, &c, 1); switch(res) { case 1: return c; case 0: /* EOF */ case -1: /* error */ } }