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

マルチスレッドの構造

従来の UNIX でもスレッドという概念はすでにサポートされています。各プロセスは 1 つのスレッドを含むので、複数のプロセスを使うようにプログラミングすれば、複数のスレッドを使うことになります。しかし、1 つのプロセスは 1 つのアドレス空間でもあるので、1 つのプロセスを生成すると 1 つの新しいアドレス空間が作成されます。

新しいプロセスを生成するのに比べると、スレッドを生成するのはシステムへの負荷ははるかに小さくなります。これは、新たに生成されるスレッドが現在のプロセスのアドレス空間を使用するからです。スレッドの切り替えに要する時間は、プロセスの切り替えに要する時間よりもかなり短いです。その理由の 1 つは、スレッドを切り替える上でアドレス空間を切り替える必要がないことです。

同じプロセスに属するスレッド間の通信は簡単に実現できます。それらのスレッドは、アドレス空間を含めあらゆるものを共有しているからです。したがって、あるスレッドで生成されたデータを、他のすべてのスレッドがただちに利用できます。

マルチスレッドをサポートするインタフェースは、サブルーチンライブラリで提供されます (POSIX スレッド用は libpthread で、Solaris スレッド用は libthread です)。カーネルレベルとユーザレベルのリソースを切り離すことによって、マルチスレッドは柔軟性をもたらします。

ユーザレベルのスレッド

スレッドは、マルチスレッドのプログラミングにおいて基本となるプログラミングインタフェースです。ユーザレベルのスレッド [ユーザレベルのスレッドという呼称は、システムプログラマだけが関係するカーネルレベルのスレッドと区別するためのものです。このマニュアルは、アプリケーションプログラマ向けであるため、カーネルレベルのスレッドについては触れません。] はユーザ空間で処理されるため、カーネルのコンテキストスイッチの負荷を増やすことはありません。何百ものスレッドを使用するようなアプリケーションでも、カーネルのリソースをそれほど使用しなくてもすみます。どのくらいの量のカーネルリソースをアプリケーションが必要とするかは、主にアプリケーション自体の性質で決まります。

スレッドは、それらが存在するプロセスの内部からだけ参照でき、アドレス空間や開いているファイルなどすべてのプロセスリソースを共有します。スレッドごとに固有な状態としては次のものがあります。

スレッドはプロセスの命令とそのデータの大半を共有するので、あるスレッドが行なった共有データの変更は、プロセスの他のすべてのスレッドから参照できます。スレッドが自分と同じプロセス内の他のスレッドとやり取りを行う場合は、オペレーティング環境を介する必要はありません。

デフォルトでは、スレッドは非常に軽量です。しかし、スレッドをより厳格に制御したいアプリケーションでは (たとえば、スケジューリングの方針をより厳密に適用したい場合など)、スレッドを結合できます。アプリケーションがスレッドを実行リソースに結合すると、そのスレッドはカーネルのリソースとなります (詳細は、「システムスコープ (結合スレッド)」を参照してください)。

以下に、ユーザレベルのスレッドの利点を要約します。

軽量プロセス

スレッドライブラリは、カーネルによってサポートされる軽量プロセス (LWP) と呼ばれる制御スレッドを基礎としています。LWP は、コードやシステムコールを実行する仮想的な CPU と考えることができます。

通常、スレッドを使用するプログラミングで LWP を意識する必要はありません。以下に述べる LWP の説明は、「プロセススコープ (非結合スレッド)」で述べるスケジューリングスコープの違いを理解する際の参考にしてください。


注 -

Solaris 2、Solaris 7、および Solaris 8 オペレーティング環境の LWP と SunOSTM 4.0 LWP ライブラリの LWP は同じものではありません。後者は Solaris 2、Solaris 7、および Solaris 8 オペレーティング環境ではサポートされていません。


fopen()fread() などの stdio ライブラリルーチンが open()read() などのシステムコールを使用するのと同じように、スレッドインタフェースも LWP インタフェースを使用します。

軽量プロセス (LWP) はユーザレベルとカーネルレベルの橋渡しをします。各プロセスは 1 つ以上の LWP を含み、それぞれの LWP は 1 つ以上のユーザスレッドを実行します ( 図 1-1 を参照)。スレッドが生成されるときは、通常それに伴ってユーザのコンテキストが作成されますが、LWP は生成されません。

図 1-1 ユーザレベルスレッドと軽量プロセス

Graphic

各 LWP はカーネルプールの中のカーネルリソースであり、スレッドに割り当てられ (接続され) たり、割り当てを解除され (切り離され) たりします。この割り当て / 割り当て解除はスレッド単位ごとに、スレッドがスケジュールされるか、生成または破棄されたときに行われます。