2012-07-26 10 views
87

Linuxでは、SIGTERMやSIGHUPなどのシグナル(複数のスレッドを持つ可能性があります)が受け取られるとどうなりますか?Linuxでの複数スレッドによるシグナル処理

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

答えて

30

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

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

2.6では、SIGTERMは子スレッドを「きれいに」終了させます。2.4では、子スレッドは不定状態のままです。

+0

そして、何信号を受信したときにルートスレッド内で起こりますか?私がSIGUSR1用のカスタムシグナルハンドラを書き、今はそのシグナルをプロセスに送信しているとしましょう。ルートスレッドはそのシグナルを取得します。おそらくそれはその瞬間のある機能の真中にあります。何が起こるでしょうか? –

+1

ハンドラの設定がある場合、割り込みとして扱われ、プログラムの流れは停止し、カスタムハンドラが実行されます。実行されると、通常のフロー(exitなど)を変更するために何もしなかったと仮定して、制御が戻ります。 – Alan

+0

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

102

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_UNKILLABLE | SIGNAL_GROUP_EXIT)) && 
     !sigismember(&t->real_blocked, sig) && 
     (sig == SIGKILL || !t->ptrace)) { 
      /* 
      * This signal will be fatal to the whole group. 
      */ 

、あなたがいることがわかりは、信号が届く場所を担当しています。

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

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

いくつかの信号が、しかし、特別です:

A signal may be generated (and thus pending) for a process as 
    a whole (e.g., when sent using kill(2)) or for a specific 
    thread (e.g., certain signals, such as SIGSEGV and SIGFPE, 
    generated as a consequence of executing a specific machine- 
    language instruction are thread directed, as are signals 
    targeted at a specific thread using pthread_kill(3)). A 
    process-directed signal may be delivered to any one of the 
    threads that does not currently have the signal blocked. If 
    more than one of the threads has the signal unblocked, then 
    the kernel chooses an arbitrary thread to which to deliver 
    the signal. 
+6

カーネルコードを抜粋してくれてありがとう!非常に役立ちます。 – cheshirekow

関連する問題