Unix(Posix)プロセスがシグナルを受信すると、シグナルハンドラが実行されます。
マルチスレッドプロセスでは何が起こりますか?どのスレッドが信号を受信しますか?
私はこの問題を処理するためにシグナルAPIを拡張する必要があると思います(つまり、シグナルハンドラのスレッドを決定できるはずです)。しかし、オンラインで情報を検索してみると、Linuxカーネルメーリングリストや他のフォーラムで1年以上の議論がありました。 。私が理解している限り、Linusの概念はPosix標準とは異なり、いくつかの互換性層が最初に構築されましたが、Linuxはposixモデルに従います。
現状はどうですか?
答え1
POSIXのアイテム」信号の生成と送信「は、「基本:システムインターフェースの一般情報」に記載されています。
プロセスに対して生成された信号は、1つのスレッドにのみ転送されます。したがって、複数のスレッドが信号を受信できる場合は、1つのスレッドを選択する必要があります。スレッドの選択は完全に実装に依存し、可能な限り最も広く一貫した実装を可能にし、実装が「最も簡単な」スレッドにシグナルを伝達する自由を提供します(転送の容易さがスレッドごとに異なる場合)。
~からsignal(7)
Linuxシステムマニュアル:
プロセス全体に対してシグナルが生成(したがって一時停止)される可能性があります(たとえば、次を使用する場合)。
kill(2)
)または特定のスレッド(特定の機械語命令の実行によって生成されたSIGSEGVやSIGFPEなどの特定の信号)は、特定のスレッドの信号と同様にスレッド指向です。pthread_kill(3)
)。プロセス制御信号は、現在の信号をブロックしていない任意のスレッドに転送できます。複数のスレッドのシグナルがブロックされない場合、カーネルはシグナルを転送するスレッドを選択します。
そしてpthreads(7)
:
スレッドには異なる代替信号スタック設定があります。ただし、新しいスレッドのバックアップシグナルスタック設定はスレッドを作成したスレッドからコピーされるため、スレッドは最初にバックアップシグナルスタックを共有します(カーネル2.6.16で修正)。
~からpthreads(3)
OpenBSDシステムマニュアル(代替アプローチの例):
シグナルハンドラは通常、現在の実行スレッドのスタックで実行されます。
(現在、マルチプロセッサシステムで複数のスレッドが同時に実行されたときにそれを処理する方法がわかりません。)
POSIXスレッドの以前のLinuxThread実装では、異なる個々のスレッドのみがシグナルの宛先になることができました。 ~からpthreads(7)
Linuxシステムの場合:
LinuxThreads はプロセス指向信号の概念をサポートしていません。シグナルは特定のスレッドにのみ送信できます。
答え2
より実用的な視点を持つために受け入れられた答えを拡張して、私が見つけたものここ。
本質は次のとおりです。
シグナルハンドラはプロセスごとに処理されますが、シグナルマスクはスレッドごとに処理されます。
- したがって、シグナルハンドラを取り付ける/取り外すと(使用して信号()またはシグアクション())すべてのスレッドはすべてのスレッドに影響を与えます。
- プロセスがシグナルを受け取ると、ハンドラは単一スレッドでのみ実行されます。スレッドはその中で疑似ランダムに選択され、そのスレッドの信号マスクがそれを受け入れます。私の実験では、常にPIDが最小のスレッドであることがわかりました。*
- スレッドに送信された信号は、基本プロセスに送信された信号と見なされます。したがって、あるスレッドがシグナルを受け取ると、別のスレッドがハンドラを実行する可能性が高くなります。スレッド(sとして識別され、スレッドID)が保護されたプロセス(sとして識別)として処理され、
tid
aに送信された信号がそれに転送されることを確認したら。pid
tid
pid
- 信号ハンドラを実行するために与えられた信号番号は、信号マスクに自動的にマスクされる。これは、スタックされた信号ハンドラが信号バーストで実行されるのを防ぐためです。これはという
SA_NODEFER
フラグで変更できますsigaction(...)
。 - (3)と(4)の結果は、信号バーストの場合、システムが信号処理手順を最も並列な方法で配布できることです。
- しかし、sigactionを設定
SA_NODEFER
すると常に同じスレッドが信号を受信してスタックされます。。
*コメントには、最初に生成されたスレッドである可能性があることが示されています。どちらもposix仕様なので、コードで信頼しないでください。