【问题标题】:Terminal Input with timeout (thread + timer + cin)带超时的终端输入(线程 + 定时器 + cin)
【发布时间】:2021-09-24 16:59:15
【问题描述】:

我想启动一个控制台程序(qt、c++)并询问用户是要加载以前的设置还是设置新的设置。 10秒无输入后,我想自动加载设置。

我的做法:

  • 使用 qTimer 和附加线程启动程序
  • 通过 std::cin 向用户询问他在附加线程中的输入
  • 如果没有输入则触发计时器以退出线程并继续主程序

我面临的问题是,我无法以编程方式中止 std::cin。即使退出线程也不会中止 std::cin。

所以我想我的方法不对,实现我的总体目标的最佳方法是什么?

【问题讨论】:

  • cin 用于简单的输入,在 C++ 目标和 C++ 几乎所有目标的每个系统上都可以正常工作。要在控制台读取超时,您通常必须使用特定于操作系统的功能。在 POSIX 系统上,我会从 read 和 select 开始(主要是因为我遇到的超时问题要少得多 select 比 read)。在 Windows 下... 不得不说我从来没有在 Windows 中这样做过。但是杀死线程来结束任务是你几乎不应该做的事情。它会使程序处于不稳定状态。
  • 也就是说,我现在才意识到问题中提到了 qt。去挖掘 qt API。很有可能 qt 内置了一些东西可以为你做这件事,或者足够接近你可以包裹它或用锤子敲打它,直到你得到你想要的东西。

标签: c++ qt cin


【解决方案1】:

根据您提到的线程,我猜测其意图是允许用户在控制台提示符下输入文本,而不会阻塞 Qt 事件循环。在这种情况下,您可能可以通过使用QSocketNotifier 来避免显式使用线程。

下面的例子演示了基本思想...

#include <cstdio>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <QCoreApplication>
#include <QSocketNotifier>
#include <QTimer>

int
main (int argc, char **argv)
{
  try {
    QCoreApplication app(argc, argv);
    QTimer timeout;

    /*
     * Create a QSocketNotifier and let it monitor stdin/std::cin.  The
     * connected lambda just reads one char at a time here.
     */
    QSocketNotifier stdin_notifier(::fileno(stdin), QSocketNotifier::Read);
    QObject::connect(&stdin_notifier, &QSocketNotifier::activated,
                     [&](QSocketDescriptor socket, QSocketNotifier::Type type)
                       {

                         /*
                          * We've received input so stop the timer and read a
                          * single char.
                          */
                         timeout.stop();
                         char c;
                         ::read(::fileno(stdin), &c, 1);
                         std::cout << "stdin: read `" << c << "'\n";
                       });

    /*
     * Start with a 5 second timeout.
     */
    unsigned remaining = 5;
    std::cout << "you have " << remaining << "s to start entering text\r" << std::flush;
    QObject::connect(&timeout, &QTimer::timeout,
                     [&]
                       {
                         if (!--remaining) {
                           std::cout << std::left << std::setfill(' ') << std::setw(50)
                                     << "too late" << "\n";
                           app.quit();
                         } else {
                           std::cout << "you have " << remaining
                                     << "s to start entering text\r" << std::flush;
                         }
                       });
    timeout.start(1000);
    exit(app.exec());
  }
  catch (std::exception &ex) {
    std::cerr << ex.what() << "\n";
  }
  catch (...) {
    std::cerr << "unrecognized exception\n";
  }
  exit(1);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-03
    • 2014-07-22
    相关资源
    最近更新 更多