マルチスレッドのプログラミング

タイマー、アラーム、およびプロファイル

LWP ごとのタイマー (timer_create(3RT) を参照) とスレッドごとのアラーム (alarm(2) または setitimer(2) を参照) についての「サポート中止」のご案内が Solaris 2.5 リリースでされています。どちらの機能も、この節で説明するプロセスごとの代替物によって置き換えられています。

各 LWP は、その LWP に結合されているスレッドが使用できるリアルタイムインターバルタイマーとアラームを持っています。このタイマーとアラームは、一定時間が経過すると 1 つのシグナルをスレッドに送ります。

各 LWP は、その LWP に結合されているスレッドが使用できる仮想時間インターバルタイマー、またはプロファイル用のインターバルタイマーも持っています。このインターバルタイマーは一定時間が経過すると、それを所有している LWP に SIGVTALRM シグナルまたは SIGPROF シグナルを送ります。

LWP ごとの POSIX タイマー

Solaris 2.3 と 2.4 リリースでは、timer_create(3RT) 関数が戻すタイマーオブジェクトは、そのタイマー ID が呼び出し LWP の中だけで意味をもち、その期限切れシグナルが呼び出し LWP に送られるというものでした。このため、POSIX タイマ機能を使用できるスレッドは、結合スレッドに限られていました。

さらに、この制限された使用方法でも、Solaris 2.3 と 2.4 リリースのマルチスレッドアプリケーションでの POSIX タイマーは、生成されるシグナルのマスキングおよび sigvent 構造体からの関連値の送信について信頼性に欠けるところがありました。

Solaris 2.5 以降のリリースでは、マクロ _POSIX_PER_PROCESS_TIMERS を定義してコンパイルされたアプリケーション、あるいはシンボル _POSIX_C_SOURCE に対して 199506L より大きな値を指定してコンパイルされたアプリケーションは、プロセスごとのタイマーを作成できます。

Solaris 9 オペレーティング環境では、仮想時間およびプロファイルのインターバルタイマーを除いて、すべてプロセスごとのタイマーが使用されます (ITIMER_VIRTUALITIMER_PROF については setitimer (2) を参照)。仮想時間およびプロファイルのタイマーは、LWP ごとになっています。

プロセスごとのタイマーのタイマー ID は、どの LWP からでも使用できます。期限切れシグナルは、特定の LWP に向けられるのではなく、そのプロセスに対して生成されます。

プロセスごとのタイマーは、timer_delete(3RT) の呼び出し時またはそのプロセスの終了時にのみ削除されます。

スレッドごとのアラーム

Solaris オペレーティング環境 2.3 と 2.4 リリースでは、alarm(2) または setitimer(2) の呼び出しは、呼び出し LWP の中だけで意味をもっていました。生成した LWP が終了すると、こうしたタイマーは自動的に削除されました。このため、alarm()setitimer() を使用できるスレッドは、結合スレッドに限られていました。

さらに制限された使用方法でも、Solaris オペレーティング環境 2.3 と 2.4 のマルチスレッドアプリケーションでの alarm() タイマーと setitimer() タイマーは、これらの呼び出しを行なった結合スレッドからのシグナルのマスキングについて信頼性に欠けるところがありました。このようなマスキングが必要とされなければ、結合スレッドから出された、これら 2 つのシステムコールの動作は信頼できるものでした。

Solaris オペレーティング環境 2.5 以降のリリースでは、-lpthread (POSIX) スレッドとリンクしたアプリケーションは、alarm() を呼び出したときにプロセスごとの SIGALRM 通知を受け取ります。alarm() で生成される SIGALRM は、特定の LWP に向けられるのではなく、そのプロセスに対して生成されます。このアラームは、そのプロセスの終了時にリセットされます。

Solaris オペレーティング環境 2.5 リリースより前のリリースでコンパイルされたアプリケーション、あるいは -lpthread とリンクされていないアプリケーションは、alarm() または setitimer() で生成されるシグナルの、LWP ごとの送信を引き続き行います。

Solaris 9 オペレーティング環境では、 alarm() または setitimer(ITIMER_REAL) を呼び出すと、SIGALRM シグナルが戻り値としてプロセスに送信されます。

プロファイル

Solaris 2.6 より前の リリースでは、profil() をマルチスレッドプログラムから呼び出すと、呼び出した LWP にだけ適用されます。プロファイルの状態は、LWP の作成時には継承されません。 グローバルプロファイルバッファを使用してマルチスレッドプログラムにプロファイルを適用するには、各スレッドを起動するときに profil() を呼び出す必要があります。また、各スレッドは、結合スレッドでなければなりません。これは面倒で、プロファイルの動的な切り替えは簡単ではありませんでした。Solaris 2.6 以降のリリースでは、マルチスレッドプロセスから profil() システム呼び出しを行うと、大域的に適用されます。つまり、profil() を呼び出すと、プロセス内のすべての LWP およびスレッドに適用されます。 これにより、以前の LWP ごとの方式に依存したアプリケーションは、使用できなくなることがあります。しかし、実行時に動的にプロファイルを切り替えたい場合の状況を改善するものと期待されます。