web-dev-qa-db-ja.com

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

Linuxでは、SIGTERMやSIGHUPなどのプログラム(おそらく複数のスレッドを持つ)がシグナルを受信するとどうなりますか?

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

111
user500944

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

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

2.6では、SIGTERMは子スレッドを「クリーンに」終了させますが、2.4では、子スレッドは不確定な状態のままでした。

35
Alan

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

  • 信号の性質

POSIX.1では、次のようないくつかの属性が各スレッドに対してdistinctである必要もあります。

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.
         */

そのため、youが信号の配信先を管理していることがわかります。

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

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

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

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

123
sarnold