Linuxでの複数のスレッドによる信号処理


119

Linuxでは、プログラム(複数のスレッドがある可能性がある)がSIGTERMやSIGHUPなどのシグナルを受信するとどうなりますか?

どのスレッドがシグナルをインターセプトしますか?複数のスレッドが同じシグナルを取得できますか?シグナルの処理専用の特別なスレッドはありますか?そうでない場合、シグナルを処理するスレッド内で何が起こりますか?シグナルハンドラルーチンが終了した後、実行はどのように再開されますか?

回答:


35

これは、使用しているLinuxカーネルのバージョンに基づいて、わずかに微妙に異なります。

2.6 posixスレッドを想定し、OSがSIGTERMまたはSIGHUPを送信することについて話している場合、シグナルはプロセスに送信され、プロセスはルートスレッドによって受信されて処理されます。POSIXスレッドを使用すると、SIGTERMを個々のスレッドに送信することもできますが、OSがプロセスにシグナルを送信したときに何が起こるかについて質問しているのではないかと思います。

2.6では、SIGTERMによって子スレッドが「正常に」終了します。2.4の場合、子スレッドは不確定な状態のままでした。


そして、シグナルが受信されると、ルートスレッド内で何が起こりますか?SIGUSR1のカスタムシグナルハンドラーを作成し、そのシグナルをプロセスに送信するとします。ルートスレッドはそのシグナルを受け取ります。たぶん、それはその時点でいくつかの機能の真ん中にあります。何が起こりますか?

1
ハンドラーセットアップがある場合、それは割り込みとして扱われ、プログラムフローが停止し、カスタムハンドラーが実行されます。実行すると、通常のフローを変更するために何もしなかった場合(終了など)に、制御が戻ります。
アラン

これは、SIRCがシステムコールを中断しないSIGUSR1に固有のものであることに注意してください。たとえばSIGINTでこれを試みた場合、ストリームの読み取りが中断される可能性があり、読み取りに戻ると、ストリームは中断されたというエラーを返す可能性があります。
アラン

10
「ルートスレッド」の意味について少し混乱しています。これは、SIGTERMのハンドラが常にメインスレッドで実行されることを意味しますか、それとも任意のスレッドで実行できますか?
Stephen Nutt 2014年

3
この答えは、信号を処理するために任意のスレッドが選択されていると述べていますが、あなたの答えとは矛盾しています。
user202729

134

pthreads(7) POSIX.1は、プロセス共有属性内のすべてのスレッドが必要であることを説明しています。

  • 信号処理

POSIX.1では、各スレッドで異なるいくつかの属性も必要です。

Linuxカーネルのcomplete_signalルーチンには、次のコードブロックがあります。コメントは非常に役立ちます。

/*
 * Now find a thread we can wake up to take the signal off the queue.
 *
 * If the main thread wants the signal, it gets first crack.
 * Probably the least surprising to the average bear.
 */
if (wants_signal(sig, p))
        t = p;
else if (!group || thread_group_empty(p))
        /*
         * There is just one thread and it does not need to be woken.
         * It will dequeue unblocked signals before it runs again.
         */
        return;
else {
        /*
         * Otherwise try to find a suitable thread.
         */
        t = signal->curr_target;
        while (!wants_signal(sig, t)) {
                t = next_thread(t);
                if (t == signal->curr_target)
                        /*
                         * No thread needs to be woken.
                         * Any eligible threads will see
                         * the signal in the queue soon.
                         */
                        return;
        }
        signal->curr_target = t;
}

/*
 * Found a killable thread.  If the signal will be fatal,
 * then start taking the whole group down immediately.
 */
if (sig_fatal(p, sig) &&
    !(signal->flags & SIGNAL_GROUP_EXIT) &&
    !sigismember(&t->real_blocked, sig) &&
    (sig == SIGKILL || !p->ptrace)) {
        /*
         * This signal will be fatal to the whole group.
         */

だから、あなたはあなたがが信号が配信される場所を担当しが:

プロセスがシグナルの処理をSIG_IGNまたはに設定した場合SIG_DFLに、シグナルはすべてのスレッドで無視されます(またはデフォルト-kill、core、またはignore)。

プロセスがシグナルの性質を特定のハンドラルーチンに設定している場合は、次のコマンドを使用して特定のスレッドシグナルマスクを操作することにより、シグナルを受信するスレッドを制御できます。 pthread_sigmask(3)。1つのスレッドを指定してそれらすべてを管理するか、シグナルごとに1つのスレッドを作成するか、特定のシグナルに対してこれらのオプションを組み合わせて作成するか、シグナルをメインスレッドに配信するというLinuxカーネルの現在のデフォルトの動作を利用できます。

ただし、signal(7)manページによれば、一部のシグナルは特別です。

シグナルは、プロセス全体(たとえば、kill(2)を使用し送信された場合)または特定のスレッド(たとえば、実行の結果として生成されたSIGSEGVやSIGFPEなどの特定のシグナル)に対して生成(および保留)されます。特定の機械語命令はスレッド向けであり、pthread_kill(3)を使用して特定のスレッドをターゲットとする信号も同様 です。プロセス向けのシグナルは、現在シグナルがブロックされていないスレッドのいずれかに配信されます。複数のスレッドでシグナルのブロックが解除されている場合、カーネルはシグナルを配信する任意のスレッドを選択します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.