C++ stdin 偶尔会出现乱码
C++ stdin occasionally garbled
最近几天我遇到了一个偶尔会发生的奇怪错误。
我有一个控制台应用程序,它还显示 window 使用 SDL 打开以连续 运行 三个线程进行图形输出。主线程运行事件循环,并处理控制台输入。第二个线程使用 std::cin.getline
获取控制台输入。然而,这第二个线程也负责输出日志信息,当用户点击 SDL 上的某处时可以产生日志信息 window。
这些日志消息被发送到受互斥锁保护的 stringstream
,线程 2 会定期检查它。如果有日志消息,它会删除提示,输出它们,然后打印一个新提示。由于这个原因,它不能在 getline
上阻塞,因此该线程生成第三个线程 peek
s cin
并在有数据时通过 atomic
发出信号从输入流中获取,此时调用 getline
并将输入传递给主线程上的逻辑。
这是我还没有完全解决的一点,其中大约有三分之一失败,因为程序没有收到与输入到终端中的输入完全相同的输入。你可以在图像 here 中看到我的意思,第一行是类型,第二行是 Lua 堆栈跟踪,因为接收到不同的(不正确的)输入。
无论我是否使用 rlwrap
都会出现这种情况。这是因为 peek
和 getline
同时访问了输入流吗? (这是可能的,因为 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 所指出的,对流的并发访问是明确禁止的,因此这清楚地解释了修复工作的原因。
最近几天我遇到了一个偶尔会发生的奇怪错误。
我有一个控制台应用程序,它还显示 window 使用 SDL 打开以连续 运行 三个线程进行图形输出。主线程运行事件循环,并处理控制台输入。第二个线程使用 std::cin.getline
获取控制台输入。然而,这第二个线程也负责输出日志信息,当用户点击 SDL 上的某处时可以产生日志信息 window。
这些日志消息被发送到受互斥锁保护的 stringstream
,线程 2 会定期检查它。如果有日志消息,它会删除提示,输出它们,然后打印一个新提示。由于这个原因,它不能在 getline
上阻塞,因此该线程生成第三个线程 peek
s cin
并在有数据时通过 atomic
发出信号从输入流中获取,此时调用 getline
并将输入传递给主线程上的逻辑。
这是我还没有完全解决的一点,其中大约有三分之一失败,因为程序没有收到与输入到终端中的输入完全相同的输入。你可以在图像 here 中看到我的意思,第一行是类型,第二行是 Lua 堆栈跟踪,因为接收到不同的(不正确的)输入。
无论我是否使用 rlwrap
都会出现这种情况。这是因为 peek
和 getline
同时访问了输入流吗? (这是可能的,因为 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 所指出的,对流的并发访问是明确禁止的,因此这清楚地解释了修复工作的原因。