3

大量の処理を行う小さなプログラムがあります。エンターキーを押すと、その進行状況を印刷できます。

私がこれを実装した方法は、メイン スレッドで処理を実行する一方で、Enter キーを待機するために getchar() で pthread を常にループさせることです。

問題は、処理が終わったときです。これが発生すると、メイン スレッドは終了しますが、getchar() がブロックされているため、Enter キーが押されるのを待機します。

getchar() を「キャンセル」するにはどうすればよいですか?

4

5 に答える 5

4

私が考えることができる最も移植性の高いソリューションは次のとおりです。

  • pipe()リーダーとライターの 2 つの FD を構築するために使用します。read()あなたのループにリーダーを渡してください。リーダーを終了する必要がある人にライターを渡します。
  • 読み取りスレッドから使​​用select()して、stdin とリーダー パイプの両方が読み取り可能になるのを待ちます。
  • stdin が読み取り可能になったら、文字を読み取って処理し、ループを再開します。
  • リーダー パイプが読み取り可能になったら、それを閉じてループを終了します。

ここで、パイプのもう一方の端を閉じるだけで、リーダー スレッドが起動し、select()終了します。

従来のアプローチにはシグナルの使用が含まれますが、このパイプベースのソリューションでは、stdin での入力をチェックしたり、同じポーリング メカニズムを使用して終了する必要があるかどうかをチェックしたりできます。


getchar()と の混合select()は機能しないことに注意してください。これは、getchar()が内部で効果的に使用fread()され、 で実行されるバッファリングにより、利用可能なデータがあってもブロックされるfread()可能性があるためです。代わりにselect()使用してください。read()これは、このアプローチをテストするために使用したプログラムの例です。

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/select.h>

void * entry_point(void * p) {
    int readpipe = *(int *)p;
    fd_set rfds;

    char c;

    for (;;) {
        FD_ZERO(&rfds);
        FD_SET(STDIN_FILENO, &rfds);
        FD_SET(readpipe, &rfds);

        while (select(readpipe + 1, &rfds, NULL, NULL, NULL) == 0);

        if (FD_ISSET(readpipe, &rfds)) {
            close(readpipe);
            break;
        }

        if (FD_ISSET(STDIN_FILENO, &rfds)) {
            if (read(STDIN_FILENO, &c, sizeof(c)) > 0) {
                printf("Read: %d\n", c);
            }
        }
    }

    printf("Thread terminating\n");

    pthread_exit(NULL);
}

int main() {
    pthread_t thread;
    int r;
    int pipes[2];

    pipe(pipes);

    if (r = pthread_create(&thread, NULL, entry_point, &pipes[0])) {
        printf("Error: %d\n", r);
        return 1;
    }

    sleep(5);

    printf("Closing pipe and joining thread.\n");

    close(pipes[1]);
    pthread_join(thread, NULL);

    pthread_exit(NULL);
}

実行例:

$ time ./test
1
Read: 49
Read: 10
2
Read: 50
Read: 10
3
Read: 51
Read: 10
4
Read: 52
Read: 10
5
Read: 53
Read: 10
Closing pipe and joining thread.
Thread terminating

real    0m5.004s
user    0m0.004s
sys     0m0.000s
于 2012-07-16T22:58:26.940 に答える
0

このパスをたどりたいと仮定すると、pthread_kill を使用して getchar スレッドを強制的に終了させることができます。Pthread ライブラリの Kill Thread を参照してください。繰り返しますが、最良のプログラミング方法ではありません。

于 2012-07-16T22:42:43.067 に答える
0

共有変数を持つことについてはどうですか。次に、 getchar() が戻るたびにロックを取得し、この共有変数が設定されているかどうかを確認します。そうでない場合は、実行していることが何でも実行されます。設定されている場合は、スレッドが終了します。このようにして、メインが終了するときに、ロックを取得し、変数を設定し、ロックを解放し、標準入力に出力し、他のスレッドが終了するのを待ちます。少し複雑ですが、うまくいくはずです。〜ベン

于 2012-07-17T00:19:40.823 に答える
-1

printf() を使用して stdin に文字を書き込みます。

于 2012-07-16T22:47:32.247 に答える
-1

締めくくりの標準入力のアイデアが本当に好きです。これは問題なく、うまくいく可能性があります。

以下は stdin を閉じます: close(0); fclose(標準入力); 閉じる (STDIN_FILENO); デーモン (0, 0);

また、メイン スレッドから標準入力に特殊な文字シーケンスまたは EOF を書き込むだけで、シャットダウンすることもできます。

于 2012-07-16T22:49:39.197 に答える