`CancelIoEx` 与 Windows 控制台中 `getline` 的输入取消问题剖析
2024-03-27 12:47:40
Windows 控制台中的 CancelIoEx
和 getline
:一次取消输入的深层探讨
在 Windows 控制台中处理用户输入时,有时需要取消异步输入操作,例如 ReadFile
和 WriteFile
。CancelIoEx
函数通常用于此目的,但当它与 getline
一起使用时,可能会出现一些意外行为。
问题
当使用 CancelIoEx
异步取消 Windows 控制台输入时,getline
无法完全被取消。用户需要输入内容两次(按两次回车键)才能触发下一次 getline
。
可能的解决方案
猜测 Windows 控制台中的某些内容可能无法被 CancelIoEx
正确取消,从而导致此问题。
代码示例
以下 C++ 示例代码演示了此问题:
#include <iostream>
#include <thread>
#include <string>
#include <windows.h>
using namespace std;
HANDLE hStdin = nullptr;
void readInput() {
string input;
while (true) {
cout << endl << "input: ";
getline(std::cin, input);
if (cin.good())
cout << "got msg: " << input << std::endl;
else
{
cin.clear();
}
}
}
void CancelInputPeriodically() {
while (true) {
this_thread::sleep_for(std::chrono::seconds(7));
CancelIoEx(hStdin, nullptr);
cout << "time's up!!!" << endl;
}
}
int main() {
hStdin = GetStdHandle(STD_INPUT_HANDLE);
thread cancelThread(CancelInputPeriodically);
readInput();
cancelThread.join();
return 0;
}
调试和分析
通过在 getline
处设置断点,我们发现它实际上没有收到第一次按回车键。
解决方法
一种解决方法是使用 WriteConsoleInput
函数在 cin
遇到 EOF 后发送 VK_RETURN
虚拟键。
其他注意事项
- 确保
hStdin
在主线程中正确初始化,以便CancelIoEx
可以成功取消输入。 CancelIoEx
只能取消异步输入操作,例如ReadFile
和WriteFile
。它无法取消同步输入操作,例如scanf
和gets
。
结论
虽然 CancelIoEx
对于取消 Windows 控制台中的异步输入操作非常有用,但在与 getline
一起使用时可能会遇到一些限制。通过了解其工作原理和解决方法,我们可以充分利用 CancelIoEx
的能力,在应用程序中有效地管理输入。
常见问题解答
- 为什么
CancelIoEx
无法完全取消getline
?
getline
内部使用缓存,因此在调用 CancelIoEx
之前,它可能已经将一些输入读取到缓存中。
- 如何解决此问题?
在 cin
遇到 EOF 后,使用 WriteConsoleInput
函数发送 VK_RETURN
虚拟键。
- 什么时候使用
CancelIoEx
比较合适?
当需要在未完成时取消异步输入操作时,CancelIoEx
非常有用,例如当需要响应用户输入或其他事件时。
CancelIoEx
和GetOverlappedResult
之间有什么区别?
CancelIoEx
用于取消异步输入操作,而 GetOverlappedResult
用于获取异步输入操作的结果,包括是否已取消。
- 使用
CancelIoEx
有什么限制?
CancelIoEx
只能取消异步输入操作,并且必须在操作完成之前调用。