3

Linux で実行するように設計された C で書かれた小さなアプリがあります。アプリの一部はキーボードからのユーザー入力を受け入れ、各キーストロークに応答できるように非正規端末モードを使用します。

入力を受け入れるコードのセクションは、ループ内で繰り返し呼び出される単純な関数です。

char get_input()
{
    char c = 0;
    int res = read(input_terminal, &c, 1);
    if (res == 0) return 0;
    if (res == -1) { /* snip error handling */ }
    return c;
}

これにより、端末から 1 文字が読み取られます。特定の時間枠 (termios 構造体の c_cc[VTIME] 値で指定) 内に入力が受信されない場合、read() は 0 を返し、get_input() が再度呼び出されます。

これはすべてうまく機能しますが、ターミナル ウィンドウでこのアプリを実行し、アプリを終了せずにターミナル ウィンドウを閉じると、アプリは終了せず、CPU を集中的に使用する無限ループに入り、read() が継続的に実行されることを最近発見しました。待機せずに 0 を返します。

では、ターミナル ウィンドウからアプリを実行した後、ターミナル ウィンドウを閉じた場合、アプリを正常に終了させるにはどうすればよいでしょうか。問題は、read() が -1 を返さないことです。そのため、エラー状態は、read() が 0 を返す通常のケースと見分けがつきません。したがって、私が見る唯一の解決策は、タイマーを入れて、次の場合にエラー状態があると想定することです。 read は、c_cc[V_TIME] で指定された時間よりも速く 0 を返します。しかし、その解決策はせいぜいハッキリしているように思えます。この状況を処理するためのより良い方法があることを望んでいました.

アイデアや提案はありますか?

4

3 に答える 3

1

プログラムが終了する前に、シグナルをキャッチしてリセットしていますか?SIGHUPはあなたが集中する必要があるものだと思います。read()クリーンアップから戻ったときにスイッチがオンになっている場合は、シグナルハンドラーにスイッチを設定して終了する可能性があります。

于 2009-07-26T16:47:40.703 に答える
1

端末設定ではなく、select でタイムアウトを処理する必要があります。端末がタイムアウトなしで構成されている場合、EOF を除いて読み取り時に 0 を返すことはありません。

Select はタイムアウトを提供し、read はクローズ時に 0 を提供します。

rc = select(...);
if(rc > 0) {
        char c = 0;
        int res = read(input_terminal, &c, 1);
        if (res == 0) {/* EOF detected, close your app ?*/}
        if (res == -1) { /* snip error handling */ }
        return c;
} else if (rc == 0) {
   /* timeout */
   return 0;
} else {
   /* handle select error */
}
于 2009-09-03T08:55:13.760 に答える
0

読み取りは、EOF で 0 を返す必要があります。つまり、何も正常に読み取られません。その場合、関数は 0 を返します!

あなたがすべきことは、read から返された値を 1 と比較し、例外を処理することです。つまり、あなたはそれを求めましたが、あなたはそれを手に入れましたか?

-1 が返された場合は、おそらく errno==EINTR を処理する必要があります。

char get_input()
{
        char c = 0;
        int res = read(input_terminal, &c, 1);
        スイッチ(レス) {
        ケース 1:
                cを返します。
        ケース 0:
                /* EOF */
        ケース-1:
                /* エラー */
        }
}
于 2009-09-03T08:26:43.080 に答える