Неблокирующий консольный ввод C ++ - PullRequest
30 голосов
/ 30 мая 2011

Я ищу (мультиплатформенный) способ сделать неблокирующий ввод с консоли для моей программы на C ++, чтобы я мог обрабатывать пользовательские команды, пока программа работает постоянно.Программа также будет выводить информацию одновременно.

Какой самый лучший / самый простой способ сделать это?У меня нет проблем с использованием внешних библиотек, таких как boost, если они используют разрешительную лицензию.

Ответы [ 9 ]

9 голосов
/ 30 мая 2011

Я бы сделал это, создав отдельный поток, который вызывает обычные блокирующие функции ввода-вывода и передал бы ему функцию обратного вызова, которую он вызывал бы, когда получал ввод. Вы уверены, что должны делать то, что, как вы сказали, вы хотите сделать?

Что касается одновременного вывода информации, что произойдет, если пользователь наберет какой-то текст, а вы что-то напечатали?

8 голосов
/ 12 декабря 2017

Пример использования 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 голосов
/ 04 мая 2015

Есть один простой способ:

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 поток.Что касается меня, это работает.

4 голосов
/ 30 мая 2011

Я сделал это на QNX4.5, который не поддерживает потоки или Boost, используя select.В основном вы передаете select STDIN как дескриптор файла для использования, и 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);
      }
   }
}
3 голосов
/ 05 апреля 2016

Неблокирующий консольный ввод C ++?

Ответ: выполните консольный ввод-вывод в фоновом потоке и обеспечьте средства связи между потоками.

Вот полный ((но упрощенно) тестовая программа, которая реализует асинхронный ввод-вывод, откладывая ввод-вывод в фоновый поток.

программа будет ждать, пока вы введете строки (завершите с новой строки) на консоли, а затем выполните 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?
2 голосов
/ 30 мая 2011

ncurses может быть хорошим кандидатом.

0 голосов
/ 27 декабря 2015

libuv - это кроссплатформенная библиотека C для асинхронного ввода-вывода. Он использует цикл обработки событий, например, чтение со стандартного ввода без блокировки потока. libuv - это то, что поддерживает Node.JS и другие.

0 голосов
/ 01 апреля 2013

Вы можете использовать библиотеку tinycon для этого. Просто создайте объект tinycon в новом потоке, и вы почти закончили. Вы можете определить метод триггера, который будет запускать все, что вы захотите, когда нажмете Enter.

Вы можете найти его здесь: https://sourceforge.net/projects/tinycon/

Кроме того, лицензия BSD, поэтому она будет наиболее разрешительной для ваших нужд.

0 голосов
/ 31 мая 2011

Класс StdinDataIO сетевой библиотеки MUSCLE с лицензией BSD поддерживает неблокирующее чтение со стандартного ввода в Windows, MacOS / X и Linux / Unix ... вы можете использоватьэто (или просто изучить код в качестве примера того, как это можно сделать), если хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...