C++ stdin 偶尔会出现乱码

C++ stdin occasionally garbled

最近几天我遇到了一个偶尔会发生的奇怪错误。

我有一个控制台应用程序,它还显示 window 使用 SDL 打开以连续 运行 三个线程进行图形输出。主线程运行事件循环,并处理控制台输入。第二个线程使用 std::cin.getline 获取控制台输入。然而,这第二个线程也负责输出日志信息,当用户点击 SDL 上的某处时可以产生日志信息 window。

这些日志消息被发送到受互斥锁保护的 stringstream,线程 2 会定期检查它。如果有日志消息,它会删除提示,输出它们,然后打印一个新提示。由于这个原因,它不能在 getline 上阻塞,因此该线程生成第三个线程 peeks cin 并在有数据时通过 atomic 发出信号从输入流中获取,此时调用 getline 并将输入传递给主线程上的逻辑。

这是我还没有完全解决的一点,其中大约有三分之一失败,因为程序没有收到与输入到终端中的输入完全相同的输入。你可以在图像 here 中看到我的意思,第一行是类型,第二行是 Lua 堆栈跟踪,因为接收到不同的(不正确的)输入。

无论我是否使用 rlwrap 都会出现这种情况。这是因为 peekgetline 同时访问了输入流吗? (这是可能的,因为 peek 循环看起来像:

while(!exitRequested_)
{
  if (std::cin.peek())
    inputAvailable_ = true; // this is atomic

  std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

有什么想法吗?看了一下curses,不过看起来用起来还是挺费力气的。我以前从未听说过 get line 乱码。但我也打印了一段时间内收到的每个字符串,它们与 Lua 报告的内容相匹配。

正如@davmac 所建议的,peek 似乎一直在干扰 getline。我的假设是,这与 peek 获取一个字符然后在 getline 获取缓冲区的同时将其放回原处有关。

无论问题的根本原因是什么,我 >98% 确定问题已通过实施 davmac 建议的修复得到解决。 在几个小时的使用中,我没有遇到任何问题。

道德,不要并发访问 cin,即使其中一个函数不修改流。

(请注意,以上内容发生在 g++ 和 clang++ 上,所以我假设它只是与 std 库的频繁实现方式有关)。

正如@DavidSchwartz 所指出的,对流的并发访问是明确禁止的,因此这清楚地解释了修复工作的原因。