C++ 中非阻塞式的用户输入

作者: , 共 1290 字 , 共阅读 0

如果我们用std::getline或者简单的std::cin >>获取用户输入,有一个问题是,它会阻塞掉整个程序,用户必须有输入后才能继续执行。如果这个输入是单独的线程,它还会阻止整个程序的退出。

这个时候可以用下面这个函数,非阻塞式的用户输入,会检查用户是否在输入,没有的话就直接返回空:

#include <iostream>
#include <optional>

std::optional<std::string> noblock_input(std::istream& in = std::cin)
{
    // 下面这个很关键
    in.sync_with_stdio(false);

    if (in.rdbuf()->in_avail() > 0) {
        char buffer[1024];

        in.getline(buffer, sizeof(buffer));

        return buffer;
    }

    return {};
}

注意,该实现在用户已有输入字符的情况下,会等到用户输入到按下回车为止,在这期间是也是阻塞的。

也有人提到

The only C++ function that comes close to what you're asking is std::cin.rdbuf()->in_avail(): http://www.cplusplus.com/reference/streambuf/streambuf/in_avail/

But it won't help you to do what you're describing: std::cin's buffer is not updated when the user presses a key. It is only updated when you, the programmer, attempt to make a read from std::cin and its buffer happens to be empty, so it has to ask the OS for input.

If you're trying to build a keyboard-interactive game, use a gaming library that provides such functionality, or the underlying OS API. (for POSIX OS, the API is select()/poll(), combined with appropriate tty driver settings)

所以上述实现有可能依赖于特定的编译器和命令行客户端。该实现在 ubuntu 20.04 / GCC 9.4 / windows terminal 下测试有效。

Q. E. D.

类似文章:
编程 » C++
在实现C++中非阻塞式的用户输入中发现,在没有设置in.sync_with_stdio(false)时,in.rdbuf()里面总是空的。
编程 » C++
要在C++中运行系统命令,可以直接使用std::system函数:
编程 » C++, popen
popen函数可以获取比std::system函数更详细的程序输出。只是正常调用 popen 只能获取 stdout 的输出,而 stderr 的输出被忽略。
编程 » C++
有两种方法,一种在线程的调用函数内部设置,还有一种是在外部对指定线程变量做设置。
编程 » C++, fmt
最近遇到一个诡异的问题,一个程序经常卡死。最后定位到 fmt 和下面简单的例子:
std::thread是 C++ 11 新引入的标准线程库。在同样是 C++ 11 新引入的 lambda 函数的辅助下,std::thread用起来特别方便:
编程 » C++, 智能指针
理论上而言,当 C++提供了std::unique_ptr, C++的程序就不应该出现普通指针了。所有普通指针都可以用std::unique_ptr代替,避免手动删除对象。
编程 » C++
现在一般不能用 sprintf 和 strcpy ,推荐使用 snprintf 和 strncpy ,以防止缓冲区溢出:
编程 » C++, C++标准库
std::tuple的原理并不复杂,但有些细节非常有意思。其中有一个是至少在gnu C++ std的实现中,std::tuple是倒序存储的:
编程 » C++, 编译
一个典型的 GCC C++编译过程为:
跟着绿野的商业队伍去妫水河骑行,每人 198 元,惠新西街南口大巴接送往返。自行车取车地是世界葡萄博览园的南门。自驾也可以在此处租车,每车 150 元。
IT » cronjob
第一步,在当前服务器导出计划任务: