POSIXスレッドとPOSIXシグナルの相互作用の複雑さを理解しようとしています。特に、私は興味があります:
これが必要な理由については、スレッドをサポートするために TclX パッケージを変換する方法、または分割して少なくともいくつかの有用な部分がスレッドをサポートするようにする方法を調査しています。信号は、特に重要な部分の1つです。
- 信号が配信されるスレッドを制御する最良の方法は何ですか?
@ zoli2kが示したように、単一のスレッドを明示的に指定して、処理するすべてのシグナル(または特定のシグナルを処理する一連のスレッド)を処理することは、優れた手法です。
- 信号が到着したことを別のスレッド(実際にはビジーである可能性があります)に伝える最良の方法は何ですか?[...]
- シグナルが発生したという情報を他のスレッドに渡すことを安全に処理するにはどうすればよいですか?これはシグナルハンドラで発生する必要がありますか?
「ベスト」とは言いませんが、私のおすすめは次のとおりです。
すべてのスレッドがそのシグナルマスクを継承するように、main
で必要なすべてのシグナルをブロックします。次に、特別なシグナル受信スレッドをシグナル駆動イベントループとして作成し、新しく到着したシグナルを他のスレッド内通信としてディスパッチします。
これを行う最も簡単な方法は、スレッドに sigwaitinfo
またはsigtimedwait
を使用してループ内のシグナルを許可させることです。その後、スレッドは何らかの方法で信号を変換し、おそらくpthread_cond_t
をブロードキャストし、他のスレッドをより多くのI/Oで起動し、アプリケーション固有のスレッドセーフキューにコマンドをキューに入れます。
あるいは、特別なスレッドを使用して、シグナルをシグナルハンドラに配信し、シグナルを処理する準備ができたときにのみ配信のマスクを解除することもできます。 (ただし、ハンドラーを介したシグナル配信は、sigwait
ファミリーを介したシグナル受け入れよりもエラーが発生しやすい傾向があります。)この場合、レシーバーのシグナルハンドラーは、いくつかの単純で非同期シグナルセーフなアクションを実行します:sig_atomic_t
フラグの設定、sigaddset(&signals_i_have_seen_recently, latest_sig)
、write
()を呼び出して、非ブロッキング self-pipe などのバイトにします。その後、スレッドはマスクされたメインループに戻り、通信します上記のように他のスレッドへのシグナルの受信。
([〜#〜] updated [〜#〜]@cafは、sigwait
アプローチが優れていることを正しく指摘しています。)
POSIX規格によれば、すべてのスレッドはシステム上で同じPIDで表示され、pthread_sigmask()
を使用して、すべてのスレッドのシグナルブロックマスクを定義できます。
PIDごとに定義できるシグナルハンドラは1つだけなので、1つのスレッドですべてのシグナルを処理し、実行中のスレッドをキャンセルする必要がある場合はpthread_cancel()
を送信します。 pthread_kill()
に対して推奨される方法です。スレッドのクリーンアップ関数を定義できるためです。
一部の古いシステムでは、適切なカーネルサポートがないため、実行中のスレッドのPIDが親スレッドのPIDと異なる場合があります。 Linux 2.4上のlinuxThreads を使用した信号処理については、FAQを参照してください。
私見、Unix Vシグナルとposixスレッドはうまく混ざりません。 Unix Vは1970です。POSIXは1980です;)
キャンセルポイントがあり、1つのアプリケーションでシグナルとpthreadを許可すると、最終的に各呼び出しの周りにループを作成することになり、驚くほどEINTRを返す可能性があります。
そのため、LinuxまたはQNXでマルチスレッドをプログラムしなければならない(ごく少数の)ケースで私がしたことは、すべての(ただし1つの)スレッドのすべてのシグナルをマスクすることでした。
Unix Vシグナルが到着すると、プロセスはスタックを切り替えます(プロセス内で取得できるのと同程度のUnix Vの並行性)。
ここの他の投稿が示唆しているように、どのposixスレッドがそのスタックスイッチングの犠牲になるかをシステムに伝えることが可能になるかもしれません。
シグナルハンドラスレッドを機能させることができたら、問題は残ります。シグナル情報を他のスレッドが使用できる文明的なものに変換する方法です。スレッド間通信のインフラストラクチャが必要です。有用なパターンの1つに、各スレッドがインプロセスメッセージングメカニズムのターゲットとなるアクターパターンがあります。
そのため、他のスレッドをキャンセルまたは殺す(または他の奇妙なもの)の代わりに、SignalコンテキストからSignalハンドラースレッドにSignalをマーシャルしてから、アクターパターン通信メカニズムを使用して意味的に有用なメッセージをそれらのアクターに送信する必要があります、信号関連情報が必要な人。
これまでのところ:
signal
対sigaction
、pselect
、sigwait
、sigaltstack
、およびその他のビットをソートする必要がありますPOSIX(および非POSIX)APIの一部。