非阻塞控制台输入C++

Dou*_*oug 31 c++ io console nonblocking

我正在寻找一种(多平台)方式为我的C++程序执行非阻塞控制台输入,因此我可以在程序不断运行时处理用户命令.该计划还将同时输出信息.

什么是最好/最简单的方法?只要他们使用许可许可证,我就可以使用像boost这样的外部库.

Set*_*gie 9

我会通过创建一个单独的线程来实现这一点,该线程调用正常的阻塞IO函数并传递一个回调函数,它在输入时会调用它.你确定你需要做你想说的事吗?

至于同时输出信息,如果用户正在键入一些输入并且你打印了一些内容会发生什么?

  • @Doug你不应该真的从不同的线程输出和输入控制台(除非你想让一些同步对象保持一致,这可能会导致你首先使用线程的原因去血本无归).我之前没有尝试过,但我想如果你从一个线程打印一些东西而另一个线程正在等待输入并且用户命中输入,那么等待输入的那个将获得另一个输出作为输入的一部分.所以事情会变得混乱.就像我说的那样,我没有尝试过. (2认同)
  • 我最终使用线程和输入和输出队列与一对互斥.该线程处理所有控制台i/o. (2认同)

Sas*_*cha 9

使用C ++ 11的示例:

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

static std::string getAnswer()
{    
    std::string answer;
    std::cin >> answer;
    return answer;
}

int main()
{

    std::chrono::seconds timeout(5);
    std::cout << "Do you even lift?" << std::endl << std::flush;
    std::string answer = "maybe"; //default to maybe
    std::future<std::string> future = std::async(getAnswer);
    if (future.wait_for(timeout) == std::future_status::ready)
        answer = future.get();

    std::cout << "the answer was: " << answer << std::endl;
    exit(0);
}
Run Code Online (Sandbox Code Playgroud)

在线编译器:https : //rextester.com/GLAZ31262

  • 这个解决方案实际上是有误导性的。getAnswer 中的 std::cin 仍然阻塞,但您没有注意到这一点,因为您从 main 调用它,然后调用 exit。退出清理线程并刷新/关闭流。如果您要将几乎整个主体从 main 移动到另一个由 main 调用的函数中 - 如本示例所示:https://rextester.com/DIWL84093 - 您将看到使用 future 的函数永远不会返回。因为 std::cin 仍然会阻止并阻止未来的返回。 (9认同)

sas*_*ang 5

我已经在不支持线程或 Boost 的 QNX4.5 上使用select. 您基本上将selectSTDIN 作为要使用的文件描述符传递,并且 select 将在输入新行时返回。我在下面添加了一个简化的示例循环。它是独立于平台的,至少对于类 Unix 系统而言是这样。虽然不确定Windows。

while (!g_quit)
{
   //we want to receive data from stdin so add these file
   //descriptors to the file descriptor set. These also have to be reset
   //within the loop since select modifies the sets.
   FD_ZERO(&read_fds);
   FD_SET(STDIN_FILENO, &read_fds);

   result = select(sfd + 1, &read_fds, NULL, NULL, NULL);
   if (result == -1 && errno != EINTR)
   {
      cerr << "Error in select: " << strerror(errno) << "\n";
      break;
   }
   else if (result == -1 && errno == EINTR)
   {
      //we've received and interrupt - handle this
      ....
   }
   else
   {
      if (FD_ISSET(STDIN_FILENO, &read_fds))
      {
         process_cmd(sfd);
      }
   }
}
Run Code Online (Sandbox Code Playgroud)


Ric*_*ges 5

非阻塞控制台输入 C++ ?

Ans:在后台线程上执行控制台 IO 并提供线程之间的通信方式。

这是一个完整(但简单)的测试程序,它通过将 io 延迟到后台线程来实现异步 io。

该程序将等待您在控制台上输入字符串(以换行符终止),然后对该字符串执行 10 秒的操作。

您可以在操作进行时输入另一个字符串。

输入 'quit' 使程序在下一个周期停止。

#include <iostream>
#include <memory>
#include <string>
#include <future>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>

int main()
{
    std::mutex m;
    std::condition_variable cv;
    std::string new_string;
    bool error = false;

    auto io_thread = std::thread([&]{
        std::string s;
        while(!error && std::getline(std::cin, s, '\n'))
        {
            auto lock = std::unique_lock<std::mutex>(m);
            new_string = std::move(s);
            if (new_string == "quit") {
                error = true;
            }
            lock.unlock();
            cv.notify_all();
        }
        auto lock = std::unique_lock<std::mutex>(m);
        error = true;
        lock.unlock();
        cv.notify_all();
    });

    auto current_string = std::string();
    for ( ;; )
    {
        auto lock = std::unique_lock<std::mutex>(m);
        cv.wait(lock, [&] { return error || (current_string != new_string); });
        if (error)
        {
            break;
        }
        current_string = new_string;
        lock.unlock();

        // now use the string that arrived from our non-blocking stream
        std::cout << "new string: " << current_string;
        std::cout.flush();
        for (int i = 0 ; i < 10 ; ++i) {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            std::cout << " " << i;
            std::cout.flush();
        }
        std::cout << ". done. next?\n";
        std::cout.flush();
    }
    io_thread.join();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

示例测试运行:

$ ./async.cpp
first
new string: first 0 1las 2t 3
 4 5 6 7 8 9. done. next?
new string: last 0 1 2 3 4 5 6 7 8quit 9. done. next?
Run Code Online (Sandbox Code Playgroud)

  • 你如何在没有“退出”的情况下向 `io_thread` 发出信号退出?`getline` 被阻塞 (6认同)