pthread_sigmask(3THR) は、スレッドのシグナルマスクを設定するための関数です。つまり、sigprocmask(2) がプロセスに対して行うのと同じ操作をスレッドに対して行います。新しいスレッドが生成されると、その初期状態のシグナルマスクは生成元から継承されます。
マルチスレッドプロセス内で sigprocmask() を呼び出すのは、pthread_sigmask() を呼び出すのと同等です。詳細は、sigprocmask(2) のマニュアルページを参照してください。
pthread_kill(3THR) は、スレッド用の kill(2) で、特定のスレッドにシグナルを送ります。スレッドにシグナルを送った場合は、プロセスにシグナルを送った場合と異なります。プロセスに送られたシグナルは、プロセス内のどのスレッドでも処理できます。pthread_kill() で送られたシグナルは、指定されたスレッドだけが処理できます。
pthread_kill() でシグナルを送ることができるのは、現在のプロセス内のスレッドに限られることに注意してください。スレッド識別子
(thread_t
型) の有効範囲が局所的であるため、現在のプロセス以外のプロセス内のスレッドを指定できないからです。
宛先のスレッドでシグナルの受信時に行われる処置 (ハンドラ、SIG_DFL、SIG_IGN) は通常どおり広域的です。この意味は、たとえば、あるスレッドに SIGXXX を送信する場合、そのプロセスにとっての SIGXXX シグナル処置がそのプロセスを終了させることであれば、宛先スレッドがこのシグナルを受け取ったとき、そのプロセス全体が終了するということです。
マルチスレッドプログラムでは、sigwait(2) が好まれるインタフェースです。これは、非同期的に生成されるシグナルを正しく処理できるからです。
sigwait() は、set 引数に指定したシグナルが呼び出しスレッドに送られてくるまで、そのスレッドを待ち状態にします。スレッドが待っている間は、set 引数で指定したシグナルのマスクが解除され、復帰時に元のシグナルマスクが設定し直されます。
set 引数で識別されるすべてのシグナルは、呼び出しスレッドを含むすべてのスレッドでブロックする必要があります。そうしないと、sigwait() は正確に動作しません。
非同期シグナルからプロセス内のスレッドを隔離したい場合は、sigwait() を使用します。非同期シグナルを待つスレッドを 1 つ生成しておき、他のスレッドは、現在のプロセスに送られてくる可能性のある非同期シグナルをすべてブロックするように生成します。
Solaris オペレーティング環境 2.5 以降のリリースでは、Solaris オペレーティング環境 2.5 バージョンの新しい sigwait() と POSIX.1c バージョンの sigwait() の 2 種類を使用できます。新しいアプリケーションとライブラリでは、できるだけ POSIX 規格インタフェースを使用してください。Solaris オペレーティング環境バージョンは、将来のリリースではサポートされない可能性があるからです。
これら 2 つのバージョンの sigwait() の構文は下記のとおりです。
#include <signal.h> /* Solaris 2.5 バージョン */ int sigwait(sigset_t *set); /* POSIX.1c バージョン */ int sigwait(const sigset_t *set, int *sig); |
指定のシグナルが送られてくると、POSIX.1c sigwait() は保留されているそのシグナルを削除し、sig にそのシグナルの番号を入れます。同時に複数のスレッドから sigwait() を呼び出すこともできますが、受け取るシグナルごとに 1 つのスレッドだけの sigwait() だけが返ってきます。
sigwait() を使うと、非同期シグナルを同期的に扱うことができます。つまり、非同期シグナルを扱うスレッドから sigwait() だけを呼び出すと、シグナルが到着しだい戻ります。sigwait() の呼び出し側も含むすべてのスレッドで非同期シグナルをマスクすることによって、非同期シグナルを特定のシグナルハンドラだけに処理させることができます。非同期シグナルを安全に処理することが可能です。
すべてのスレッドですべてのシグナルを常にマスクし、必要なときだけ sigwait() を呼び出すようにすれば、アプリケーションはシグナルに依存するスレッドに対してはるかに安全になります。
通常はsigwait() を呼び出すスレッドを 1 つ以上作成して、シグナルを待機します。sigwait() はマスクされているシグナルであっても受け取るため、それ以外のスレッドでは誤ってシグナルを受け取ることがないように、対象となるシグナルをすべてブロックしてください。
シグナルを受け取ったスレッドは、 sigwait() から戻ってそのシグナルを処理し、sigwait() を再度呼び出して次のシグナルを待機します。 このシグナル処理スレッドでは、非同期シグナル安全関数以外の関数も使用でき、ほかのスレッドとも通常の方法で同期をとることができます。非同期シグナル安全カテゴリについては、マルチスレッドインタフェースの安全レベルを参照してください。
sigwait() は、同期的に生成されたシグナルを受け取ることができません。
sigtimedwait(3RT) は、指定時間が経過してもシグナルが送られてこなかったときにエラーで復帰する点を除いて、sigwait(2) と似ています。