Linuxでは、プログラム(複数のスレッドがある可能性がある)がSIGTERMやSIGHUPなどのシグナルを受信するとどうなりますか?
どのスレッドがシグナルをインターセプトしますか?複数のスレッドが同じシグナルを取得できますか?シグナルの処理専用の特別なスレッドはありますか?そうでない場合、シグナルを処理するスレッド内で何が起こりますか?シグナルハンドラルーチンが終了した後、実行はどのように再開されますか?
Linuxでは、プログラム(複数のスレッドがある可能性がある)がSIGTERMやSIGHUPなどのシグナルを受信するとどうなりますか?
どのスレッドがシグナルをインターセプトしますか?複数のスレッドが同じシグナルを取得できますか?シグナルの処理専用の特別なスレッドはありますか?そうでない場合、シグナルを処理するスレッド内で何が起こりますか?シグナルハンドラルーチンが終了した後、実行はどのように再開されますか?
回答:
これは、使用しているLinuxカーネルのバージョンに基づいて、わずかに微妙に異なります。
2.6 posixスレッドを想定し、OSがSIGTERMまたはSIGHUPを送信することについて話している場合、シグナルはプロセスに送信され、プロセスはルートスレッドによって受信されて処理されます。POSIXスレッドを使用すると、SIGTERMを個々のスレッドに送信することもできますが、OSがプロセスにシグナルを送信したときに何が起こるかについて質問しているのではないかと思います。
2.6では、SIGTERMによって子スレッドが「正常に」終了します。2.4の場合、子スレッドは不確定な状態のままでした。
pthreads(7)
POSIX.1は、プロセス共有属性内のすべてのスレッドが必要であることを説明しています。
POSIX.1では、各スレッドで異なるいくつかの属性も必要です。
シグナルマスク(pthread_sigmask(3)
)
代替信号スタック(sigaltstack(2)
)
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)を使用して特定のスレッドをターゲットとする信号も同様 です。プロセス向けのシグナルは、現在シグナルがブロックされていないスレッドのいずれかに配信されます。複数のスレッドでシグナルのブロックが解除されている場合、カーネルはシグナルを配信する任意のスレッドを選択します。