1

標準出力に出力するコンソール アプリケーションがあります。次の動作を実装したい:

  • 出力は順番に印刷されます (各ターンの後に 2 秒の休憩)
  • ユーザーは(彼にとってはオプションです)キーを押して他のデータの印刷を開始できます
  • ユーザーが何もクリックしない場合、出力は印刷されるだけで、何も変わりません
  • ユーザーが定義済みのキーをクリックすると (出力が印刷されている間でもクリックできる場合があります)、何らかの関数を呼び出す必要があります。

最初は別のスレッド(印刷用スレッド、入力待ち用スレッド)でやろうかと思ったのですが、この場合はスレッド内で入力待ちが出来ないので無理かなと思います。

それで、それができるかもしれない2つのライブラリを見つけました:

どちらも知らないので、目標を達成するためにどちらを学べばよいかわかりません。それとも、別のより簡単な解決策がありますか?

OS: Unix

編集: g-makulik は、スレッドを使用して書き込むことができなかった理由を示すように依頼しました。

#include <pthread.h>
#include <iostream>
#include <string>
#include <stdio.h>

void* print_message_function(void *doPrint) {
    bool* vDoPrint = (bool*) doPrint;
    while (*vDoPrint) {
        sleep(0.5);
        std::cout << "Thread 1" << std::endl;
    }
    return NULL;
}

void* keyPressed(void* doPrint) {
    bool* vDoPrint = (bool*) doPrint;
    while (*vDoPrint) {
        *vDoPrint = (char) getchar() == 'k' ? false : true;
        std::cout << "THIS ISN'T DISPLAYED UNLESS 'k' PRESSED.";
    }
    return NULL;
}

int main(int argc, char* argv[]) {
    pthread_t thread1, thread2;
    int iret1, iret2;
    bool doPrint = true;
    iret2 = pthread_create(&thread2, NULL, print_message_function,
            (void*) &doPrint);
    iret1 = pthread_create(&thread1, NULL, keyPressed,
            (void*) &doPrint);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    std::cout << "Thread 1 returns: " << iret1 << std::endl;
    std::cout << "Thread 2 returns: " << iret2 << std::endl;
    return 0;
}
4

3 に答える 3

1

別のスレッドが同じコンソールに出力している間に、あるスレッドからのキーボード入力を待つことができます。スレッド (入力/出力) を同期するだけで、ユーザー入力 (イベント キューの使用など) で機能を取得できます。

編集:これらのシステムコールを提供するシステムでは、個別のスレッドの代わりにタイムアウト を使用するselect()か、タイムアウトを使用することをお勧めします。epoll()

ncurses lib を使用すると、ウィンドウのような方法でコンソール表示を整理できます (たとえば、出力を表示する別のパネルを持ち、コマンド (行) 入力の種類を持つ)。ncurses が実行できる高度なサンプルについては、Midnight Commanderを参照してください。

ただし、アプリケーションでエコーされた入力のそのような分離を気にしない限り、入力と出力の単純なスレッド分離はうまく機能します。

SMFL については何も言えませんが、このライブラリはコンソールではなくグラフィックス レベルでのウィンドウ表示をサポートしているようです。

于 2012-08-22T18:38:07.530 に答える
0

以前に ncurses を使用したことがありますが、次の解決策は最もきれいではないかもしれませんが、うまくいくはずです。

Ncurses では、入力を「遅延なし」モードにすることができます。これによりgetch()、入力から文字を読み取る がノンブロッキングになり、ユーザーが何も押していない場合はすぐに ERR が返されます。

標準入力ファイル記述子を待って、入力ファイル記述子の読み取り準備ができているかどうかを確認できます。それは、select()またはepoll()あなたが望むものです。2 秒ごとに何かをしなければならない場合は、その時間をselect()またはに入れることができますepoll()。キーを押した場合は、それで何をしたいかを決めることができます。

このソリューションにはマルチスレッドは必要ありません。

私はSFMLの知識がないので、SFMLがこれを簡単にするかどうかはわかりません. Ncurses は、C++ アプリケーションにとって便利な場合とそうでない場合がある C ライブラリです。マニュアル ページがインストールされている場合は、ncurses 関数に関するドキュメントを直接参照できる可能性があります (たとえば、man getch)。

于 2012-08-22T18:35:46.853 に答える
0

SFMLは、これまで聞いたことのないものです。これが悪い選択だとは言えませんが、あまり人気のない選択なので、プログラムのユーザーがそのためだけにインストールしなければならない可能性が高くなります。私はその道を行きません。

ncursesはかなり一般的で優れたソリューションですが、あなたの場合は複雑すぎると思います。ncurses は、画面への描画、ウィンドウの組み立て、マウスの操作など、より複雑なテキスト I/O を行う場合に非常に便利です。このような単純なアプリケーションの場合、少しやり過ぎかもしれません。一方、特定のキー押下 (テキスト入力にならない矢印キーやその他のキーなど) をキャッチしたり、マウスを処理したい場合は、ncurses が役に立ちます。

もう 1 つの一般的で軽量な選択肢はSDL (SDL_input ライブラリを使用) です。以前のソリューションとは異なり、これは単に入力指向です。これにより、キーストローク、マウス クリック、および場合によってはその他の入力イベントを非常に詳細にノンブロッキングでキャッチできます。ただし、通常は libsdl 全体をインストールします。それは小さいですが、アプリケーションのすべてのユーザーがそれを気に入ってくれるかどうかはわかりません。まあ、彼らが一般的にSDLを使用するゲームを使用しない限り.

そして最後に、このような単純なことを自分で実装できます。*nix のみ (および Windows などのシステムへの移植性ではない) に関心がある場合は、stdinノンブロッキング モードに設定し、メイン ループで反復的なノンブロッキング読み取りを使用してキー押下をチェックできます。select()アプリケーションがループ反復間の実際の処理よりも多くの待機を行う場合は、入力の遅延と待機の両方を処理する代わりに使用する方がよい場合があります。

スレッドは非効率的であり、通常、解決するよりも多くの問題を引き起こすため、その唯一の理由でスレッドを導入することは避けます。非ブロッキング I/O が実現可能な場合は、スレッド化されたブロッキング I/O を使用しないでください。

于 2012-08-22T18:38:52.610 に答える