3

2 つのスレッドを持つ C プログラムがあります。メイン スレッドは、ネットワークからデータを継続的に読み取り、それを画面に出力します。セカンダリ スレッドは、標準入力からのキー入力をリッスンして処理します。

現在、私のプログラムは、プログラムをきれいに終了するために、SIGINT、SIGTERM、および SIGPIPE をキャッチします。私の問題は、メイン スレッドの最後に (メイン ループがシグナル ハンドラから終了すると)、 を使用して端末設定を元に戻そうとすることですが、これは他のスレッドの現在の呼び出しが戻るtcsetattrまでブロックされます。fgetc

fgetc呼び出しが戻り、メインスレッドが端末設定を復元して正常に終了できるように、バックグラウンドスレッドを中断するにはどうすればよいですか?

使用してみpthread_kill(thread, SIGINT)ましたが、既存のシグナルハンドラーが再度呼び出されるだけです。

関連コード:

// If the program should still be running.
static sig_atomic_t running = 1;

// Background thread that reads keypresses.
pthread_t thread;

static void *get_keypresses();

static void receive_signal(int signal) {
    (void)signal;
    running = 0;
}

int main(int argc, char *argv[]) {
    // Set up signal handling.
    if(signal(SIGINT, receive_signal) == SIG_ERR) {
        fprintf(stderr, "Error setting signal handler for SIGINT.\n");
    }
    if(signal(SIGTERM, receive_signal) == SIG_ERR) {
        fprintf(stderr, "Error setting signal handler for SIGTERM.\n");
    }
    if(signal(SIGPIPE, receive_signal) == SIG_ERR) {
        fprintf(stderr, "Error setting signal handler for SIGPIPE.\n");
    }

    // Set up thread attributes.
    pthread_attr_t thread_attrs;
    if(pthread_attr_init(&thread_attrs) != 0) {
        perror("Unable to create thread attributes");
        exit(2);
    }
    if(pthread_attr_setdetachstate(&thread_attrs, PTHREAD_CREATE_DETACHED) != 0) {
        perror("Unable to set thread attributes");
        exit(2);
    }

    // Set up terminal for reading keypresses.
    struct termios orig_term_attr;
    struct termios new_term_attr;
    tcgetattr(fileno(stdin), &orig_term_attr);
    memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
    new_term_attr.c_lflag &= ~(ECHO|ICANON);
    tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);

    // Start background thread to read keypresses.
    if((pthread_create(&thread, &thread_attrs, &get_keypresses, NULL)) != 0) {
        perror("Unable to create thread");
        exit(2);
    }

    // Main loop.
    while(running) {
        // Read data from network and output to screen.
    }

    // Restore original terminal attributes. ***IT BLOCKS HERE***
    tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);

    return 0;
}

// Get input from the keyboard.
static void *get_keypresses() {
    int c;
    while(running) {
        // Get keypress. ***NEEDS TO BE INTERRUPTED HERE***
        if((c = fgetc(stdin)) != - 1) {
            // Handle keypress.
        }
    }
    return NULL;
}
4

4 に答える 4

2

私は自分にとってうまくいく解決策を見つけることができました.標準入力からの読み取りをノンブロッキングにしました.

fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);

これには、バックグラウンド スレッドで何らかの形式のsleep(またはusleepまたは) も必要です。nanosleep

正しい方向に考えさせてくれた HapKoM に感謝します。

于 2013-09-29T23:14:02.607 に答える