【问题标题】:C++ console input blocks so i can't kill threadC++ 控制台输入块,所以我不能杀死线程
【发布时间】:2015-02-26 22:13:55
【问题描述】:

我的程序有许多不同的线程处理不同的事情,其中​​一个处理用户输入。

其他线程没有太多阻塞调用的方式,那些阻塞调用是基于网络的,所以当套接字关闭时会被中断或优雅地返回。

但是,用户线程调用std::cin 以获取用户输入。这样做的效果是,当所有其他线程都死掉时,用户线程仍然阻塞用户输入,并且只会在下一次输入时死掉。

有什么方法可以让我在阻塞之前检查是否有任何用户输入要抓取?

我知道cin.peek() 存在,但根据我的经验,如果没有可读取的内容,它会阻塞。假设我使用正确

我的代码基本上是一个无限循环,当另一个线程切换条件变量时会停止:

void doLoop()
{
    while (running) //running is shared between all threads and all others die quickly when it is false. It's set to true before the threads are started
    {
        string input = "";
        getline(cin, input);

        //Handle Input

    }
}

我在 windows 上,使用 VS2013,不能使用外部库。我一直在使用 windows.h 和 std。

【问题讨论】:

  • 取决于您的实际操作系统,但您可能有兴趣查看select()poll() 以解决这些问题。
  • 应该提到,我在windows上
  • 当程序停止运行时,你能直接杀死用户输入线程吗?
  • 怎么杀?我将线程创建为 std::thread,并且认为没有办法远程杀死它们。我宁愿不追求这个,但主线程终止会安全地杀死剩余的线程吗?
  • @ForceGaia 这对我来说很清楚,但由于所有这些东西实际上都是依赖于操作系统的,所以你应该这样标记。 std::thread 选项可能仍会为您提供一些可行的解决方案。

标签: c++ multithreading windows-8.1 user-input blocking


【解决方案1】:

您可以做的是使用期货来允许用户输入有时间限制的内容。然后您可以将此代码插入到您的主循环中

#include <iostream>       // std::cout
#include <future>         // std::async, std::future
#include <chrono>         // std::chrono::milliseconds
#include <string>
using namespace std;


bool myAsyncGetline(string & result)
{
    std::cout<<"Enter something within the time limit"<<endl;
    getline(cin,result);
    return true;
}

int main()
{
  // call function asynchronously:
  string res;
  std::future<bool> fut = std::async (myAsyncGetline,res); 


  std::chrono::seconds span (20);
  if (fut.wait_for(span)==std::future_status::timeout)
    std::cout << "Too Late!";
  else
      cout<<"You entered "<<res<<" "<< endl;

  return 0;
}

这在 VS2012 中可用,因此您应该能够重现它。

输出是“工具迟到了!”如果超时(20s)后getline还在工作,否则输出结果。

我认为这比杀死线程更简单,因为如果达到时间限制,函数会自行停止。 如果您需要帮助将其集成到您现有的代码中,请告诉我,我可以提供帮助。

【讨论】:

  • 看起来像是一个开始的地方,但我认为它不会奏效。每次调用 myAsyncGetline 时我看到它的方式都会立即启动。因此,如果用户在该计时器的第 19 秒开始输入,一秒后它就会超时并且他们会丢失输入。然而它给了我一个想法,因为这意味着我可以继续检查一个字符串是否为空(因为当用户点击输入时它只会有一些东西),如果字符串不为空,则重新启动异步,并且我可以在循环后暂停超时,这样我就可以在线程应该死亡时终止异步。我会搞砸的。
  • 好的让我更新我很好奇我认为未来可以简化代码的bcz。
  • 是的,这就是让我质疑这种方法的原因。 fut.wait_for(span) 真的会杀死线程吗?
  • 如果超时,它将杀死它。在这里了解更多详情。 cplusplus.com/reference/future/asynccodeproject.com/Articles/857201/Cplusplus-Concurrency-New
【解决方案2】:

我相信 C++ 标准没有提供一种在不阻塞的情况下检查标准输入的方法。由于您愿意使用特定于平台的功能,“kbhit()”可能适合您的需要,但在 Windows 中已被弃用。提供了另一种选择,_kbhit()。当然,这不能移植到其他平台。

这是 MSDN 的链接:_kbhit

【讨论】:

  • 该链接提到“此 API 不能用于在 Windows 运行时执行的应用程序中”这究竟是什么意思?只有当我将其打包为 DLL 时?
  • @ForceGaia 这意味着你不能在 Windows Store 应用程序中使用它。
  • 在执行 getline 之前检查 kbhit() 如果用户已经开始输入但尚未输入,或者改变主意并中止输入文本,仍然会导致相同的问题。
  • @ForceGaia 你必须使用get() 而不是getline()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-15
  • 2018-03-09
  • 1970-01-01
  • 1970-01-01
  • 2016-09-05
  • 1970-01-01
  • 2016-08-06
相关资源
最近更新 更多