【问题标题】:How to get `cin` to read a raw mode terminal如何让`cin`读取原始模式终端
【发布时间】:2020-09-03 00:20:09
【问题描述】:

为什么标准流可以在规范模式下从终端接收输入,但是你把它放在原始模式下,突然这个方法不再有效?我非常了解 POSIX 串行编程,通常您使用read。我正在尝试更好地理解标准流。

#include <termios.h>
#include <unistd.h>
#include <iostream>

termios original;

void enableRawMode() {
  tcgetattr(STDIN_FILENO, &original);
  termios raw = original;
  cfmakeraw(&raw);
  raw.c_cc[VMIN] = 0;
  raw.c_cc[VTIME] = 1;
  tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}

int main() {
  enableRawMode();

  char c;

  // This works as expected.
  //int nread;
  //while ((nread = read(STDIN_FILENO, &c, 1)) != 1) {
  //  if (nread == -1 && errno != EAGAIN) {
  //    break;
  //  }
  //}

  // This loops forever, the failbit is always true, gcount is always 0.
  while (!(std::cin.get(c))) {
    if (std::cin.bad() || std::cin.eof()) {
      break;
    }

    std::cin.clear();
  }

  tcsetattr(STDIN_FILENO, TCSAFLUSH, &original);
}

【问题讨论】:

  • 简短的回答是否定的:这完全不切实际。您必须使用读/写并添加所有特殊逻辑(如 EAGAIN)来处理它。输入/输出流库对 EAGAIN 一无所知,也没有提供相应配置自身的方法。
  • 你尝试过不同的 VIM 和 VTIME 值吗?请参阅stackoverflow.com/questions/25996171/… 如果您的程序只是循环,那么它只是轮询系统缓冲区并浪费 CPU 周期。 “这将永远循环,...” -- 无法在 Linux 5.4 上复制此症状;程序退出,不等待任何输入!
  • @sawdust 这个例子只是从更大的整体中抽取的一个相关样本,我知道这很疯狂。请放心,我们会更加关注应用程序中的调度和流程管理。
  • @SamVarshavchik 但是,如果两者绑定和同步,为什么数据会到达标准文件描述符而不是标准流?
  • 所以你有借口使用低效的代码。我在 Linux 上获得的结果与您使用的任何 "POSIX" 操作系统有何不同?仅供参考,当 VTIME 增加到 20 时,程序在启动后 2 秒(即 20 分秒)终止。 IOW 该程序似乎确实响应了 termios 设置。你需要更彻底地调试你的程序。

标签: c++ posix iostream termios


【解决方案1】:

经过多次讨论和调查,我发现这是对给定标准流的实现的限制。基本上,我推断标准流在您的终端处于熟模式时工作正常,但如果处于原始模式则不可靠。

代码可以简化为使用std::cin.rdbuf()-&gt;sbumpc(),在这种情况下将调用uflow,这可能会调用underflow,这将从底层设备获取数据。与标准流相关的流缓冲区由实现定义。

第一次调用sbumpc,更具体地说,最终调用underflow,将在从标准输入读取时启动与VTIME 关联的计时器。如果在超时时间内收到输入,cin 将按预期工作。但如果超时,流缓冲区会进入未定义状态,sbumpc 将永远返回EOF

状态与流相关联,而不是流缓冲区,因此调用 std::cin.clear() 会清除状态标志,但不会更正流缓冲区中的潜在问题,该问题仍然存在问题。

重置搜索位置可能有解决方案,但同样,给定的标准流是实现定义的,不知道它们可能拥有什么内部状态,或者如果在一个平台上成功,在另一个平台上是否会成功.据我所知,不存在涵盖这种情况的文档。

两种可能的解决方案是直接使用 POSIX API 并喜欢它,或者编写您自己的使用 POSIX API 的流实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    • 1970-01-01
    • 2013-01-07
    相关资源
    最近更新 更多