非阻塞控制台输入C ++

时间:2011-05-29 23:34:29

标签: c++ console io nonblocking

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

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

9 个答案:

答案 0 :(得分:9)

我会通过创建一个单独的线程来执行此操作,该线程调用正常的阻塞IO函数并向其传递一个回调函数,它在输入时会调用它。你确定你需要做你想说的事吗?

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

答案 1 :(得分:4)

我在QNX4.5上使用select不支持线程或Boost。您基本上将select STDIN作为要使用的文件描述符传递,并且选择将在输入新行时返回。我在下面添加了一个简化的示例循环。它是独立于平台的,至少对于类似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);
      }
   }
}

答案 2 :(得分:4)

有一种简单的方法:

char buffer[512];
int point = 0;
...
while (_kbhit()) {
    char cur = _getch();
    if (point > 511) point = 511;
    std::cout << cur;
    if (cur != 13) buffer[point++] = cur;
    else{
        buffer[point] = '\0';
        point = 0;
        //Run(buffer);
    }
}

没有阻止,全部在1个线程中。至于我,这很有效。

答案 3 :(得分:4)

使用C ++ 11的示例:

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

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

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

    std::cout << "the answer was: " << answer << std::endl;
    exit(0);
}

在线编译器:http://rextester.com/XGX58614

答案 4 :(得分:3)

  

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

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

这是一个完整(但简单化)的测试程序,它通过将io推迟到后台线程来实现async 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;
}

样品测试运行:

$ ./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?

答案 5 :(得分:2)

ncurses可能是一个很好的候选人。

答案 6 :(得分:0)

BSD许可StdinDataIOMUSCLE networking library类支持Windows,MacOS / X和Linux / Unix下stdin的非阻塞读取...你可以使用它(或者只是检查一下)代码作为如何做的一个例子)如果你想要。

答案 7 :(得分:0)

您可以使用tinycon库来执行此操作。只是在一个新线程中生成一个tinycon对象,你就完成了。您可以定义触发方法,以便在按下输入时触发您想要的任何内容。

你可以在这里找到它: https://sourceforge.net/projects/tinycon/

此外,许可证是BSD,因此它将是您最需要的许可。

答案 8 :(得分:0)

libuv是用于异步I / O的跨平台C库。它使用事件循环来执行诸如从标准输入读取而不阻塞线程的操作。 libuv是Node.JS和其他人的强大之处。