マルチスレッドプログラムでは、sigwait(2) が好まれるインタフェースです。これは、非同期的に生成されるシグナルを非常にうまく扱えるからです。
sigwait() は、set 引数に指定したシグナルが呼び出しスレッドに送られてくるまで、そのスレッドを待ち状態にします。スレッドが待っている間は、set 引数で指定したシグナルのマスクが解除され、復帰時に元のシグナルマスクが設定し直されます。
set 引数で識別されるすべてのシグナルは、呼び出しスレッドを含むすべてのスレッドでブロックする必要があります。そうしないと、sigwait() は正確に動作しません。
非同期シグナルからプロセス内のスレッドを隔離したい場合は、sigwait() を使用します。非同期シグナルを待つスレッドを 1 つ生成しておき、他のスレッドは、現在のプロセスに送られてくる可能性のある非同期シグナルをすべてブロックするように生成します。
Solaris オペレーティング環境 2.5 以降のリリースでは、Solaris オペレーティング環境 2.5 バージョンの新しい sigwait() と POSIX.1c バージョンの sigwait() の 2 種類を使用できます。新しいアプリケーションとライブラリでは、できるだけ POSIX 規格インタフェースを使用してください。Solaris オペレーティング環境バージョンは、将来のリリースではサポートされない可能性があるからです。
Solaris オペレーティング環境 2.5 バージョンの新しい sigwait() は、シグナルの無視という処置を無効にしません。以前の sigwait(2) の動作に依存しているアプリケーションは、ダミーのシグナルハンドラをインストールして、その処置を SIG_IGN からハンドラをもつように変更しない限りブレークする可能性があるため、このシグナルに対する sigwait() 呼び出しでこのシグナルは捕捉されます。
これら 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() を決して使わないでください。