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

LWP とスケジューリングクラス

Solaris のカーネルには、プロセスのスケジューリングに関する 3 つのクラスがあります。最も優先順位が高いスケジューリングクラスは、リアルタイム (RT) クラスです。その次はシステムクラスで、ユーザプロセスには適用されません。最も低いのはタイムシェア (TS) クラスで、デフォルトのスケジューリングクラスです。

スケジューリングクラスは、LWP ごとに維持管理されます。プロセスが生成されると、そのプロセスの初期 LWP は、親プロセスのスケジューリングクラスと作成元の LWP の優先順位を継承します。その後に、非結合スレッドを実行させるために生成される LWP も、このスケジューリングクラスと優先順位を継承します。

スレッドは、関連付けられている LWP と同じスケジューリングクラスおよび優先順位を持ちます。プロセス内の各 LWP は、カーネルから参照される固有のスケジューリングクラスおよび優先順位を持つことができます。結合スレッドは、常に同じ LWP に関連付けられます。

同期オブジェクトへの競合は、スレッドの優先順位によって調節されます。デフォルトでは、LWP はタイムシェアクラスに属します。 計算が大きな比率を占めるマルチスレッドの場合、スレッドの優先順位はあまり役立ちません。MT ライブラリを使って多くの同期を行うマルチスレッドアプリケーションでは、スレッドの優先順位がより意味をもちます。

スケジューリングクラスは、システムコール priocntl(2) で設定します。最初の 2 つの引数で、この設定の適用範囲を呼び出し側の LWP に限定したり、1 つ以上のプロセスのすべての LWP にしたりすることが可能です。3 番目の引数はコマンドで、次のいずれか 1 つを指定できます。

priocntl() は、呼び出しスレッドに関連付けられた LWP のスケジューリングを制御します。 非結合スレッドの場合、priocntl() への呼び出しから制御が戻ったときに、呼び出しスレッドが元の LWP に関連付けられる保証はありません。

タイムシェアスケジューリング

タイムシェアスケジューリングでは、このスケジューリングの LWP に処理リソースが公平に配分されます。カーネルのそれ以外の部分は、ユーザーに対する応答時間に悪影響を与えないようにプロセッサを短時間ずつ使用します。

システムコール priocntl(2) は、1 つ以上のプロセスの nice() レベルを設定します。priocntl() による nice() レベルの変更は、そのプロセス内のタイムシェアクラスのすべての LWP に適用されます。nice() レベルの範囲は通常は 0〜+20 で、スーパーユーザー特権をもつプロセスの場合は -20〜+20 です。この値が小さいほど優先順位が高くなります。

タイムシェアクラスの LWP をディスパッチする優先順位は、LWP のその時点での CPU 使用率と nice() レベルに基づいて計算されます。タイムシェアスケジューラにとって、nice() レベルは、LWP 間の相対的な優先順位を表します。

LWP の nice() レベルが大きいほど、その LWP に配分される CPU 時間は少なくなりますが 0 になることはありません。多くの CPU 時間をすでに消費している LWP は、CPU 時間をほとんど (あるいは、まったく) 消費していない LWP よりも優先順位が下げられます。

リアルタイムスケジューリング

リアルタイム (RT) クラスは、プロセス全体またはプロセス内の 1 つ以上の LWP に適用できます。ただし、スーパーユーザ特権が必要です。

タイムシェアクラスの nice(2) レベルとは異なり、リアルタイムクラスを指定された LWP には、個々の LWP 単位または複数の LWP 単位で優先順位を設定できます。priocntl(2) システムコールで、プロセス内のリアルタイムクラスのすべての LWP の属性を変更できます。

スケジューラは、最も高い優先順位を持つリアルタイムクラスの LWP をディスパッチします。優先順位の高い LWP が実行可能状態になると、それよりも優先順位の低い LWP は、実行リソースを横取りされます。実行リソースを横取りされた LWP は、そのレベルの待ち行列の先頭に置かれます。

リアルタイムクラスの LWP は、実行リソースが横取りされたり、一時停止したり、リアルタイム優先順位が変更されたりしない限り、プロセッサの制御を保持し続けます。リアルタイムクラスの LWP には、タイムシェアクラスのプロセスよりも絶対的に高い優先順位が与えられます。

新しく生成された LWP は、親プロセスまたは親 LWP のスケジューリングクラスを継承します。リアルタイムクラスの LWP は、親のタイムスライス (リソース割り当て時間) を有限または無限指定に関係なく継承します。

有限タイムスライスを指定された LWP は、処理が終了するか、入出力イベント待ちなどによってブロックされるか、より優先順位の高い実行可能なリアルタイムプロセスによって実行リソースを横取りされるか、またはタイムスライスが満了するまで実行を続けます。

無限タイムスライスを指定された LWP が実行を停止するのは、LWP が終了するか、ブロックされるか、または実行リソースが横取りされたときだけです。

公平配分スケジューリング

公平配分スケジューラ (FSS) のスケジューリングクラスを使用すると、配分に基づいて CPU 時間を割り当てることができます。

デフォルトでは、FSS スケジューリングクラスでは、TS および対話型 (IA) スケジューリングクラスと同じ範囲の優先順位 (0 - 59) が使用されます。 プロセス内の LWP は、すべて同じスケジューリングクラスで実行する必要があります。 FSS クラスでは、プロセス全体ではなく、個々の LWP のスケジュールを設定します。 FSS および TS/IA のクラスを同時に使用すると、どちらのクラスも予期しないスケジュールで動作することがあります。

複数のプロセッサセットを使用する場合、それぞれのプロセッサセット上で動作するすべてのプロセスが、プロセッサごとに TS/IA または FSS スケジューリングクラスであれば、それらは同じ CPU 群に対して競合しないので、TS/IA と FSS を同時に 1 つのシステム上で使用できます。

固定優先順位スケジューリング

固定優先順位スケジューリングクラス (FX) では、優先順位および時間量に固定値を割り当てます。この値は、リソースの消費に応じて変化しません。プロセスの優先順位は、そのプロセス自体、または適切な特権が割り当てられたほかのプロセスだけが変更できます。FX については、priocntl(1) および dispadmin(1M) のマニュアルページにも記述されています。

このクラスのスレッドは、TS および 対話型 (IA) のスケジューリングクラスと同じ範囲の優先順位 (0 - 59) を共有します。 通常は、TS がデフォルトです。 FX は通常、TS といっしょに使用します。