web-dev-qa-db-ja.com

ノンブロッキングコンソール入力C ++

C++プログラムのノンブロッキングコンソール入力を行う(マルチプラットフォームの)方法を探しているので、プログラムを継続的に実行しながらユーザーコマンドを処理できます。プログラムも同時に情報を出力します。

これを行うための最良/最も簡単な方法は何ですか?寛容なライセンスを使用している限り、boostなどの外部ライブラリを使用しても問題ありません。

33
Doug

これを行うには、通常のブロッキングIO関数を呼び出すスレッドを個別に作成し、入力時に呼び出されるコールバック関数を渡します。あなたが言ったことを実行する必要がありますか?やってみたいです?

同時に情報を出力する場合、ユーザーが入力を行っている最中に何かを印刷した場合はどうなりますか?

9
Seth Carnegie

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

8
Sascha

selectを使用して、スレッドまたはBoostをサポートしないQNX4.5でこれを行いました。使用するファイル記述子として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);
      }
   }
}
4
sashang

簡単な方法が1つあります。

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
Rihard S

ノンブロッキングコンソール入力C++?

回答:コンソール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;
}

サンプルテスト実行:

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

ncurses は良い候補です。

2
Simon

StdinDataIO BSDライセンスのクラス MUSCLEネットワーキングライブラリ は、Windows、MacOS/X、およびLinux/Unixでのstdinからの非ブロッキング読み取りをサポートしています...必要に応じて(または、コードを実行する方法の例としてコードを調べてください)。

0
Jeremy Friesner

Tinyconライブラリを使用してこれを行うことができます。 tinyconオブジェクトを新しいスレッドで生成するだけで、ほとんど完了です。トリガーメソッドを定義して、Enterキーが押されたときに何でも起動することができます。

あなたはそれをここで見つけることができます: https://sourceforge.net/projects/tinycon/

また、ライセンスはBSDであるため、ニーズに最も寛容です。

0
Unix-Ninja

libuv は、非同期I/O用のクロスプラットフォームCライブラリです。イベントループを使用して、スレッドをブロックせずに標準入力から読み取るなどを行います。 libuvはNode.JSやその他の機能を強化するものです。

0
sffc