シグナルで有効にする終了条件を示すフラグがあるとします。次に、たとえば、次のハンドラーを SIGUSR1 にアタッチできます。
volatile sig_atomic_t finished = 0;
void catch_signal(int sig)
{
finished = 1;
}
次に、フラグを使用して、特定のループをいつ終了するかを決定します。この特定のケースでは、スレッドが実行されています (ただし、問題はスレッドがなくても当てはまると考えているため、その部分に焦点を当てないでください)。
void *thread_routine(void *arg)
{
while (!finished) {
/* What if the signal happens here? */
if ((clientfd = accept(sockfd, &remote_addr, &addr_size)) == -1) {
if (errno == EINTR)
continue;
/* Error handling */
}
handle_client(clientfd);
}
}
このループは、SIGUSR1 シグナルを上げるまで実行し続けることになっています。信号を受信したら、できるだけ早く正常に停止したい. 私はブロッキング受け入れ呼び出しを持っているので、CPU サイクルを浪費するループはありません。これは良いことです。シグナルはいつでもブロッキング受け入れを中断し、ループを終了させることができます。
問題は、コード内のコメントに示されているように、シグナルが while 条件の直後、accept 呼び出しの前に配信される可能性があることです。その後、シグナル ハンドラーはfinished
true に設定されますが、実行が再開された後、accept
呼び出されて無期限にブロックされます。この状態を回避し、常にシグナルでループを終了できるようにするにはどうすればよいですか?
これを制御するために信号を使用したい場合、2 つの解決策が考えられます。1つ目は、最初に信号を逃した場合にしばらくしてから信号を再発生させるアラームをオンにすることです。2 つ目は、ソケットにタイムアウトを設定して、一定時間後に受け入れが返されるようにして、フラグを再度調べることができるようにすることです。しかし、これらの解決策は回避策に似ています (特に、2 番目の解決策で受け入れのブロック動作を変更したため)。よりクリーンで簡単な解決策があれば、代わりにそれを使用したいと思います。