【问题标题】:User input without pausing code (c++ console application)无需暂停代码的用户输入(C++ 控制台应用程序)
【发布时间】:2014-11-25 10:48:00
【问题描述】:

如何输入输入而不导致代码停止执行?在过去的 20 分钟里,我一直在寻找答案,但没有结果。

cin >> string; 暂停代码 AFAIK。

我需要使用多线程,还是有更好的方法? (我什至不知道多线程是否可行。)

我最近开始学习 c++,至少可以说我是初学者,所以请详细解释并包括我可能需要的任何库,谢谢。

【问题讨论】:

  • 如果您提示输入但不等待输入就继续执行,您期望会发生什么?这似乎是一种引入竞争条件的快速方法。
  • 您将需要更详细地考虑程序的结构以及您希望它做什么。当用户输入未决时,后台应该发生什么?当用户输入可用时,该后台任务应该如何中断?这些是需要考虑的关键因素,但您没有在问题中考虑它们。
  • 有没有办法在代码运行的时候输入变量?类似while(true) {if(getConsoleInput() == "blabla") randomFunction();}
  • 这真的取决于你想做什么。如果你只是想让你的程序停止它正在做的事情,请使用kbhit() 作为建议的答案。但是,如果您正在计划诸如视频游戏之类的东西(例如),您将需要使用线程。使用 while(true) 通常很糟糕(主动等待,仅仅等待就消耗资源)。

标签: c++ multithreading console-application user-input cin


【解决方案1】:

使用 kbhit()。

while(1)
{
    if(kbhit())
    {
        // do what ever you want.
    }
}

【讨论】:

  • “我最近开始学习 c++,至少可以说我是初学者,所以请详细解释并包括我可能需要的任何库,谢谢。”我不知道我应该怎么做。我什至不能称它为:“错误:'kbhit' 未在此范围内声明”。
  • @Mandera 检查here 了解更多详细信息,但如果您解释您想要做什么,也许有更好的方法。
  • 我只是希望能够在代码运行时调用带有输入参数的函数。
  • 如果你想在函数调用期间继续你在做什么,你必须使用线程,但是如果你的主循环可能在函数调用期间停止,只需在 if( kbhit())...如果你按下一个键,这个 if 将是 True。 @曼德拉
  • 太糟糕了,这仅适用于具有kbhit() 功能的平台,这不是标准的。
【解决方案2】:

这是一个示例,说明如何使用 >> 从标准输入流中读取令牌,同时使用多线程进行另一个调用。

#include <iostream>
#include <thread>
#include <future>

int main() {
    // Enable standard literals as 2s and ""s.
    using namespace std::literals;

    // Execute lambda asyncronously.
    auto f = std::async(std::launch::async, [] {
        auto s = ""s;
        if (std::cin >> s) return s;
    });

    // Continue execution in main thread.
    while(f.wait_for(2s) != std::future_status::ready) {
        std::cout << "still waiting..." << std::endl;
    }

    std::cout << "Input was: " << f.get() << std::endl;
}

这里使用启动参数std::launch::async 调用std::async 在不同的线程上异步运行任务。 std::async 返回并行运行的任务的句柄,称为 future。这个未来可用于检查任务是否完成。任务的结果也可以使用成员函数std::future::getstd::future对象返回。

我传递给std::async 的任务是一个简单的lambda expression,它创建一个字符串,从流中读取一个标记并返回它(""s 是 C++ 中引入的标准文字14 返回一个空的std::string 对象)。

调用std::async 后,主线程继续执行语句(与异步运行任务并行)。在我的示例中,执行了一个 while 循环,它只是等待异步任务完成。请注意std::future::wait_for 的使用,每次迭代仅阻塞 2 秒。 std::future::wait_for 返回一个status,可以比较它来检查任务是否完成。

最后调用std::future::get会返回异步运行任务的结果。如果我们没有等待任务完成,调用将阻塞,直到结果准备好。

注意不要在主线程中也(并行)从标准输入中读取,因为读取调用不是原子事务并且数据可能会出现乱码。

【讨论】:

  • 哇,我称之为矫枉过正。一般来说,除非绝对必要,否则建议远离线程。有一些特定于平台的技术可以在没有显式线程的情况下使用。
【解决方案3】:

有两种算法可以在不阻塞(暂停)的情况下获取输入。第一个是轮询,第二个是按事件(中断)。

轮询输入

轮询涉及定期检查输入。使用键盘,这可能是读取键盘以进行按键操作。对于串行端口,这可能意味着检查接收寄存器的状态。

在某些系统上阻塞或等待输入将包括永远轮询,直到接收到输入。

输入事件

在某些平台上,检测到输入时会发送一个事件。例如,Windows 操作系统接收到一个按键被按下的事件,并将消息发送给焦点任务。在嵌入式系统上,硬件可以取消引用中断向量处的函数指针。

在基于事件的系统上阻塞输入意味着休眠直到收到事件。

总结

标准 C++ 语言不提供用于无阻塞地检索输入的标准函数。 C++ 输入函数的实现依赖于平台,可能会阻塞也可能不会阻塞。例如,平台可以等到收到换行符后再返回单个字符。

许多平台或操作系统都有功能,您可以在其中测试端口的输入(轮询)或在输入发生时收到通知(事件驱动)。由于您没有指定您使用的是哪个平台,所以详细信息到此为止。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 2017-03-14
    • 1970-01-01
    • 2018-07-27
    相关资源
    最近更新 更多