C++プログラムのノンブロッキングコンソール入力を行う(マルチプラットフォームの)方法を探しているので、プログラムを継続的に実行しながらユーザーコマンドを処理できます。プログラムも同時に情報を出力します。
これを行うための最良/最も簡単な方法は何ですか?寛容なライセンスを使用している限り、boostなどの外部ライブラリを使用しても問題ありません。
これを行うには、通常のブロッキングIO関数を呼び出すスレッドを個別に作成し、入力時に呼び出されるコールバック関数を渡します。あなたが言ったことを実行する必要がありますか?やってみたいです?
同時に情報を出力する場合、ユーザーが入力を行っている最中に何かを印刷した場合はどうなりますか?
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
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);
}
}
}
簡単な方法が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スレッド。私はこれでうまくいきます。
ノンブロッキングコンソール入力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?
ncurses は良い候補です。
StdinDataIO BSDライセンスのクラス MUSCLEネットワーキングライブラリ は、Windows、MacOS/X、およびLinux/Unixでのstdinからの非ブロッキング読み取りをサポートしています...必要に応じて(または、コードを実行する方法の例としてコードを調べてください)。
Tinyconライブラリを使用してこれを行うことができます。 tinyconオブジェクトを新しいスレッドで生成するだけで、ほとんど完了です。トリガーメソッドを定義して、Enterキーが押されたときに何でも起動することができます。
あなたはそれをここで見つけることができます: https://sourceforge.net/projects/tinycon/
また、ライセンスはBSDであるため、ニーズに最も寛容です。
libuv は、非同期I/O用のクロスプラットフォームCライブラリです。イベントループを使用して、スレッドをブロックせずに標準入力から読み取るなどを行います。 libuvはNode.JSやその他の機能を強化するものです。