POSIXスレッドとシグナル


81

私は、POSIXスレッドとPOSIXシグナルがどのように相互作用するかについての複雑さを理解しようとしてきました。特に、私は興味があります:

  • シグナルが配信されるスレッドを制御するための最良の方法は何ですか(そもそも致命的ではないと仮定して)?
  • シグナルが到着したことを別のスレッド(実際にはビジーである可能性があります)に伝える最良の方法は何ですか?(シグナルハンドラーからpthread条件変数を使用するのは悪い考えであることはすでに知っています。)
  • シグナルが発生したという情報を他のスレッドに渡すことを安全に処理するにはどうすればよいですか?これはシグナルハンドラーで発生する必要がありますか?(私は一般的に他のスレッドを殺したくありません;私ははるかに微妙なアプローチが必要です。)

これが必要な理由については、TclXパッケージを変換してスレッドをサポートする方法、または分割して少なくともいくつかの便利なパーツでスレッドをサポートする方法を研究しています。信号は、特に興味深い部分の1つです。

回答:


48
  • シグナルが配信されるスレッドを制御するための最良の方法は何ですか?

@ zoli2kが示しているように、処理するすべてのシグナルを処理する単一のスレッド(またはそれぞれが特定のシグナルの責任を持つスレッドのセット)を明示的に指定することは、優れた手法です。

  • シグナルが到着したことを別のスレッド(実際にはビジーである可能性があります)に伝える最良の方法は何ですか?[...]
  • シグナルが発生したという情報を他のスレッドに渡すことを安全に処理するにはどうすればよいですか?これはシグナルハンドラーで発生する必要がありますか?

「ベスト」とは言いませんが、これが私の推奨事項です。

で必要なすべてのシグナルをブロックしmainて、すべてのスレッドがそのシグナルマスクを継承するようにします。次に、特別なシグナル受信スレッドをシグナル駆動型イベントループとして作成し、新しく到着したシグナルを他のスレッド内通信としてディスパッチします。

これを行う最も簡単な方法は、sigwaitinfoまたはsigtimedwaitを使用してループ内のシグナルをスレッドに受け入れさせることです。次に、スレッドは信号を何らかの方法で変換します。おそらく、をブロードキャストしpthread_cond_t、より多くのI / Oで他のスレッドをウェイクアップし、アプリケーション固有のスレッドセーフキューでコマンドをキューに入れます。

あるいは、特別なスレッドにより、シグナルをシグナルハンドラーに配信し、シグナルを処理する準備ができた場合にのみ配信のためにマスクを解除することができます。(sigwaitただし、ハンドラーを介したシグナル配信は、ファミリーを介したシグナルの受け入れよりもエラーが発生しやすい傾向があります。)この場合、レシーバーのシグナルハンドラーはsig_atomic_t、フラグの設定、バイトの呼び出しsigaddset(&signals_i_have_seen_recently, latest_sig)write()などの単純で非同期のシグナルセーフアクションを実行します。非ブロッキング自己パイプ等、そして、バックそのマスクメインループにおいて、スレッドは、上記のように他のスレッドへの信号の受信を通信します。

更新された@cafsigwaitは、アプローチが優れていることを正しく指摘しています。)


1
これは、特に致命的ではないシグナル処理にも使用できるため、はるかに有用な答えです。ありがとう!
ドナーフェロー

1
シグナル処理スレッドがシグナルハンドラーをまったくインストールしない場合が最も簡単です。代わりに、sigwaitinfo()(またはsigtimedwait())でループし、最後の段落で説明したように、アプリケーションの残りの部分にそれらをディスパッチします。
caf

@caf、確かにそうです。更新
段落記号2015

14

POSIX標準によれば、すべてのスレッドはシステム上で同じPIDで表示される必要があり、を使用pthread_sigmask()してすべてのスレッドの信号ブロックマスクを定義できます。

PIDごとに定義できるシグナルハンドラーは1つだけなので、1つのスレッドですべてのシグナルを処理しpthread_cancel()、実行中のスレッドをキャンセルする必要がある場合は送信することをお勧めします。pthread_kill()スレッドのクリーンアップ関数を定義できるため、これは反対の方法として推奨されます。

一部の古いシステムでは、適切なカーネルサポートがないため、実行中のスレッドのPIDが親スレッドのPIDと異なる場合があります。Linux 2.4でのlinuxThreadsを使用した信号処理については、FAQを参照してください。


「実装された」とはどういう意味ですか?また、シグナルに応答して他のスレッドを常に削除することは正しくありませんが(SIGHUPとSIGWINCHはより微妙な要求があります)、他のスレッドに通知するために条件変数を使用することは安全ではありません。悪い答え。
ドナーフェロー

1
反対票を削除しましたが、シグナルに応答してスレッドを強制終了することはできないため、それでも十分な答えではありません。それに応じてローカルでイベントをキューに入れる場合もあれば、スレッドを非常に慎重に破棄する必要がある場合もあります(ところで、これらの部分を実行するためのほとんどの機械がすでにあります。これはOSへの接続です。欠落している信号)。
ドナーフェロー

1
@ zoli2k:最近make menuconfig、uClibcの新しく複製されたgitマスターブランチで実行しようとしました。POSIXスレッドの実装として古いLinuxThreadsと新しいNPTLのどちらかを選択できます、2012年現在のヘルプでは、NPTLを選択しないことを推奨しています。そのため、システムが最近十分な数のLinuxカーネルを実行している場合でも、最新の組み込みLinuxシステムでは、廃止されたLinuxThreads実装が使用されているのが一般的です。
FooF 2012年

3

私が今いるところ:

  • シグナルはさまざまな主要なクラスで提供され、通常はプロセスを強制終了するものもあれば(SIGILL)、何もする必要がないものもあります(SIGIO;非同期IOを実行する方が簡単です)。これらの2つのクラスはアクションを必要としません。
  • 一部の信号は、すぐに処理する必要はありません。SIGWINCHのようなものは、便利になるまでキューに入れることができます(X11のイベントのように)。
  • トリッキーなものは、スレッドを一掃するほどではなく、実行していることを中断することによってそれらに応答したいものです。特に、インタラクティブモードのSIGINTは、応答性を維持する必要があります。

私はまだを通じてソートに持ってsignalsigactionpselectsigwaitsigaltstack、、その他のこまごまとPOSIXの(非POSIX)APIの全体の束。


3

IMHO、Unix Vシグナル、およびposixスレッドはうまく混ざりません。Unix Vは1970年です。POSIXは1980年です;)

キャンセルポイントがあり、1つのアプリケーションでシグナルとpthreadを許可すると、最終的には各呼び出しの周りにループを作成することになり、驚くべきことにEINTRを返す可能性があります。

したがって、LinuxまたはQNXでマルチスレッドをプログラムする必要がある(いくつかの)ケースで私がしたことは、すべての(1つを除く)スレッドのすべてのシグナルをマスクすることでした。

Unix Vシグナルが到着すると、プロセスはスタックを切り替えます(これは、Unix Vではプロセス内で取得できるのと同じくらいの同時実行性でした)。

ここにある他の投稿が示唆しているように、どのposixスレッドがそのスタック切り替えの犠牲になるかをシステムに伝えることが可能かもしれません。

シグナルハンドラスレッドを機能させることができたら、問題は残ります。シグナル情報を文明化されたものに変換する方法です。他のスレッドが使用できます。スレッド間通信のインフラストラクチャが必要です。便利なパターンの1つは、各スレッドがインプロセスメッセージングメカニズムのターゲットであるアクターパターンです。

したがって、他のスレッドをキャンセルしたり、それら(または他の奇妙なもの)を強制終了したりする代わりに、SignalコンテキストからSignalハンドラースレッドにSignalをマーシャリングしてから、アクターパターン通信メカニズムを使用して、意味的に有用なメッセージをそれらのアクターに送信する必要があります。信号関連の情報が必要な人。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.