4

次のように sigaction を使用してシグナルハンドラーをセットアップしました。

struct sigaction act, oldact;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = sig_handler;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGALRM);
sigaddset(&act.sa_mask, SIGINT);
sigaddset(&act.sa_mask, SIGTERM);
sigaddset(&act.sa_mask, SIGTSTP);
sigaction(SIGALRM, &act, &oldact);
sigaction(SIGINT, &act, &oldact);
sigaction(SIGTERM, &act, &oldact);
sigaction(SIGTSTP, &act, &oldact);
act.sa_flags = 0;

これに続いて、for ループを実行して入力を収集し、それを出力します (基本的には cat のように動作します)。

char *linebuf = NULL;
size_t n = 0;
int len;
while(1){
    len = getline(&linebuf, &n, stdin);
    if(len>0){
        printf("%s", linebuf);
    }
}

ただし、シグナルの処理からgetline()戻ると、入力をブロックしなくなり、代わりに中断されたシステムコール-1を設定errnoしている間、一貫して戻ります。EINTR私は明らかに中断するつもりでしたgetline()が、入力を読み続けることができるようにリセットするにはどうすればよいですか?

私の問題を実際には解決しない同様の質問がいくつかありましたが、問題をよりよく理解するのに役立つかもしれません. 1 2

もう 1 つの興味深い情報はsignal()、シグナル処理に使用していたときにはこの問題は発生しなかったが、 sigaction()POSIX に準拠しているため変更したことです。

4

2 に答える 2

4

リンク先の質問の 1 つに、実際に回答があります。しかし、最初に、いくつかの参照があります。内部で他の関数を使用していることに注意してくださいgetline(おそらくread)。

のマニュアルページからread

read() がデータを読み取る前にシグナルによって割り込まれた場合、errno が [EINTR] に設定されて -1 が返されます。

...

... 追加の関数 select() があり、その目的は、指定されたアクティビティ (読み取るデータ、書き込むスペースなど) が指定されたファイル記述子で検出されるまで一時停止することです。これらのシステム用に作成されたアプリケーションでは、シグナルによる I/O の中断が必要な状況 (キーボード入力など) で read() の前に select() を使用するのが一般的です。

のマニュアルページからselect

pselect() 関数は、ファイル記述子セットを調べます...それらの記述子のいくつかが読み取りの準備ができているか、書き込みの準備ができているか、または保留中の例外条件があるかどうかをそれぞれ確認します。

selectそのため、いつ読み始めても安全かを知ることができます。ただし、それでもread後で中断されるのを防ぐことはできません。(私はあなたの情報のためにこれを言っただけです)。

ストリームのエラー フラグを実際にクリアするには、リンクされた質問の 1 つに対するこの回答が (C++ で) 述べているように、clearerr関数を使用してストリームのエラー フラグをクリアする必要があります。man ページ (および C 標準) では、「中断された」フラグもクリアされると具体的に述べられていませんが、それは C の範囲を超えており、POSIX の領域にあるためです。


補足として、memset構造体のクリアには使用しないでください。Cにはそれを行うための非常に良い方法があります:

struct sigaction act = {0};

または、の最初の要素が別の構造体または配列である可能性があるため、ペダントになりたい場合はstruct sigaction、その必須フィールドの 1 つに割り当てることができます。

struct sigaction act = { .sa_handler = NULL };
于 2013-10-02T15:59:20.867 に答える