【问题标题】:Loop getting cin input循环获取cin输入
【发布时间】:2017-05-03 19:25:44
【问题描述】:

是否可以像这样创建一个while循环:

bool stop_input = false;

while (!stop_input) {
    // Keep getting inputed string
    // Maybe like std::getline(std::cin, str_input);
}

这将继续循环并获取用户在控制台中输入的内容而不会停止(冻结),例如在执行std::cinstd::getline() 时。

我对此感兴趣,希望有一个单独的线程可以在等待用户输入内容并按 Enter 时执行其他操作,然后 stop_input 将变为真,并且用户输入将被禁用。

这可能吗?怎么样?

编辑:

例如,如果我这样做了:

void test()
{
    std::string str;
    while (!stop_input) {
        std::getline(std::cin, str);
    }
}

如果我创建了一个像上面这样的函数,编译它并启动一个调试器,调试器(程序)将在 std::getline() 被第二次调用时停止。我不希望这种情况发生,我希望这个循环持续运行,直到通过设置 stop_input = true; 停止。

EDIT2:

主线程:

void someFunction()
{
    string read_input;
    thread get_input = thread(readInput, &read_input);

    while(1) {
        if (buttonPressed(ENTER) {
            stop_input = true;
            get_input.join();

            // Do something with 'read_input' string.
        } else if (buttonPressed(ESC) {
           stop_input = true;
           get_input.join()

           // Discard 'read_input' string and return from this function.
           break;
        }
    }
}

阅读线程:

void readInput(string* input)
{
    while (!stop_input) {
        //Get input
    }
}

附:当然主线程也会在后面做一些工作,与输入读取无关。

【问题讨论】:

  • 您的解决方案涉及操作系统的特定功能,例如在 key按下 时收到通知或轮询以查看 key 状态 已更改。由于您没有在帖子中指明您的操作系统,因此无法进一步帮助您。在互联网上搜索“stackoverflow c++ keypress”。
  • @ThomasMatthews 我可以得到一个按键。我的问题是是否可以像描述的那样实现输入读取?
  • 您希望您的程序在按下或释放按键时中断吗?你想让你的程序poll键盘的状态吗?处理输入的不同方法。我建议将输入处理放到一个单独的线程中。
  • @ThomasMatthews 我感觉你不理解我的问题(它可能措辞不当)。忘记按键,就完成了。现在,当调用 std::cin 或 std::getling() 时,它们会冻结程序,阻止其他代码继续执行。我想要做的是,有一个单独的线程,其中 std::cin 或 std::getline() 之类的东西会运行但不会停止(冻结),它会不断运行并获取用户输入,直到一些 bool 被设置。我希望我现在说清楚了(我不是以英语为母语的人)。
  • 我不确定术语“GUI 线程”是否适用于控制台,但我认为用户输入不应来自主线程以外的任何地方。有一个主线程和一个工作线程,你需要主线程执行你的任务的原因是什么?

标签: c++ multithreading


【解决方案1】:

我不确定你的问题是否正确,但如果你只是想在线程中运行某些东西并允许输入直到线程中的任务完成,我会这样做:

std::vector< int > v;
std::atomic< bool > stop_input( false );
std::thread t( [ &v, &stop_input ]() 
{
  for( int i = 0; 1'000'000'000 > i; ++i ) v.push_back( i );
  stop_input = true;
} );
std::string m;
while( !stop_input )
{
  std::cin >> m;
  std::cout << "Your message: " << m << std::endl;
}
t.join();

但是,这只会在线程中的任务终止后用户输入后终止。它不会“中断”std::cin

【讨论】:

  • 不,正好相反,请看我最近的评论。
【解决方案2】:

你的意思是你有两个线程,一个等待用户输入然后唤醒另一个线程?

您创建一个负责处理循环的线程,然后您的另一个线程接受用户输入并设置布尔值。循环线程不断调用另一个线程来查看是否有用户输入..

像这样:

#include <iostream>
#include <thread>
#include <chrono>

using namespace std;

string s;
bool b = false;

void doStuff()
{
    int i = 0;
    while (!b)
    {
        cout << i << ' ';
        ++i;
        this_thread::yield();
        //this_thread::sleep_for(chrono::seconds(1));
    }
    cout << "you wrote: " << s << endl;
}

int main()
{
    thread t(doStuff);
    char c;
    while ((c = cin.get()) != '\n')
        s += c;
    b = true;
    t.join();
}

Sleep 和 yield 会自动阻塞线程并调用另一个可用的线程。 get() 也会自动阻塞它的线程。如果你想要非阻塞的东西,那么这可能取决于操作系统......

编辑:

您可以分离线程,使其独立执行,然后在访问共享资源之前锁定共享资源。

#include <iostream>
#include <thread>
#include <mutex>

using namespace std;

mutex m;
string s;
bool stopInput = false;

char c = 0;

void readInput()
{
    while (!stopInput)
    {
        m.lock();
        c = cin.get();
        s += c;
        m.unlock();
    }
}

int main()
{
    thread t(readInput);
    t.detach();

    while (true)
    {
        m.lock();
        if (isEnter(c))
        {
            stopInput = true;
            cout << "Input: " << s << endl;
            break;
        }
        else if (isEscape(c))
        {
            stopInput = true;
            break;
        }
        m.unlock();
    }
}

【讨论】:

    【解决方案3】:

    这个问题好像是线程同步的问题。

    假设 stop_input 本身已正确同步,例如由于它是 atomic_bool,当 stop_input 在检查后立即设置为 true 时,它​​仍然不会阻止您的线程在 while 循环的主体内执行其操作。

    您想要实现的具体目标是什么?知道了这一点,我们也许能够帮助您找到针对您的特定问题的合适的线程安全和线程感知解决方案:)

    【讨论】:

      【解决方案4】:

      可以让getline(或cin.getcin.peek 等)与“exit”变量一起在单独的线程中运行,例如“stop_input”(参见下面的示例)。

      请注意,一旦调用stop_input=true,设置getline(或cin.getcin.peek,...)显然不会中断。进一步注意,在像while (!stop_input) { std::getline(std::cin, str); ... } 这样的循环中,主线程不太可能在重新进入循环之前设置stop_input=true。所以很可能主线程不能在用户输入值后立即停止输入;在循环对stop_input 的任何更改做出反应之前,将再次输入getline

      应该进一步注意 getline 不被其他线程使用,因为 - 至少据我所知 - 它不是线程安全的。

      #include <iostream>
      #include <queue>
      #include <thread>
      #include <mutex>
      
      bool stop_input = false;
      std::queue<std::string> commandQueue;
      std::mutex commandQueueMutex;
      
      void getLineUntilInputStopped()
      {
          std::string str;
          while (!stop_input) {
              std::getline(std::cin, str);
              if (str == "stopinput")
                  stop_input = true;
      
              commandQueueMutex.lock();
              commandQueue.push(str);
              commandQueueMutex.unlock();
          }
          std::cout << "Listening on input stopped.";
      }
      
      
      int main(int argc, const char * argv[]) {
      
          std::thread t(getLineUntilInputStopped);
          t.detach();
      
          bool exit = false;
          while (!exit)
          {
              std::string command = "";
              commandQueueMutex.lock();
              if (commandQueue.size() > 0)
              {
                  command = commandQueue.front();
                  commandQueue.pop();
              }
              commandQueueMutex.unlock();
      
              if (command.size() > 0)
              {
                  if (command == "exit")
                  {
                      exit = true;
                      std::cout << "exit program.";
                  }
                  else
                  {
                      std::cout << "command '" << command << "' entered.";
                  }
              }
              else
              {
                  std::cout << "in the meanwhile do something else\n";
                  std::this_thread::sleep_for (std::chrono::seconds(3));
              }
          }
      
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-05
        • 1970-01-01
        • 2020-09-12
        • 1970-01-01
        • 2011-01-05
        • 1970-01-01
        相关资源
        最近更新 更多