「先輩,ふと思ったんですが」
「うん」
「プログラムって,どうやって動いているんでしょう」
「いきなり核心を突いてきたね。でもマシン語がどうこう,とかそういうことじゃないんだよね」
「はい。OSって何気なく使ってるんですが,これとプログラムのかかわりがちょっとわかんないんですよ」
「ふむ。じゃ,プログラムをロードするところから始めようか」

 あらためてプログラムが動く仕組みを考えてみると,OSは実に重要な役割を担っているのがわかる。さまざまなサービスの提供や,プログラムが使える資源の割り当て,状態変更の通知など,OSが提供するさまざまな機能を利用してプログラムは動作するからだ。

図1●まずプログラムをメモリ上にロードする。
これがOSの一つの役目。極端なことを言えば,MS-DOSがやっていた一番重要なサービスはこれかもしれない

 プログラムの実行をユーザが指示すると,OSは該当するプログラムを読み出してメモリ上に展開する(図1[拡大表示])。このとき,そのプログラムにさまざまな資源(リソース)を割り当てる。この資源管理が,OSの一つの重要な機能である。明示的なものとしてはメモリ空間の確保。そもそもプログラムが使う領域を確保してやらなければならない。またWindows XPやLinuxなど,まともなメモリ管理をするOSは,あるプロセスが別のプロセスのメモリを書き換えられないようにしている。書き換えようとしたプログラムはエラーを発生する注1)。

 ほかにプログラムに割り当てられる資源としては,CPU(処理を実行するためのもの),周辺機器を仮想化したデバイスなどである。これらを割り当てる単位を「プロセス」と呼ぶ。マルチプロセスのOSでは,CPU時間をある程度(タイムスライス)割り当てたら,プロセスを切り替えて実行する。その際に,利用する論理メモリ空間や仮想デバイスと実デバイスの関連づけなどの作業が発生する(コンテキスト・スイッチ)。だからプロセスの切り替えはオーバヘッドが小さくない。これに対し「スレッド」は,同じプロセスの中でCPUの処理時間を切り替えるものである注2)。したがってプロセス切り替えほどのオーバヘッドはない。ただし当然のことだが,スレッド間で同じ資源を共有して利用する場合には,プログラムのなかで排他制御をしなければならない。

サービスを利用するフックの役割を果たす

図2●ライブラリの大きな役割。
OSが提供するさまざまなサービスとプログラムをつなぐ役割を果たす

 もう一つ重要な役割が,サービスの提供である。サービスとは具体的に言えば,ファイルへのアクセスや通信制御,画面制御などさまざまなものがある。通常はAPI(Application Programming Interface)という形で実装されており,プログラムからはこういったAPIを呼び出すためのライブラリを通じてサービスを利用する(図2[拡大表示])。

 ライブラリには二つの意味がある。一つは,言語あるいは言語処理系に特化した標準的な呼び出し手順を定義しておくことにより,将来あるいはほかのプラットフォームとの互換性を高めること。もう一つは,複雑な手順を隠蔽することによって,プログラミングを簡素化することである。ただしこういった手順を簡素化するライブラリを使わず,直接ダイナミック・リンク・ライブラリなどのAPIを呼び出すことも可能である。

 もう少しこの意味について考えてみよう。例えば,いわゆる標準Cライブラリ。標準Cライブラリでは,コンソールへの出力に「printf()」,キーボード入力に「getchar()」などの関数を使う。裸のOSのAPIがそのままprintfだったりgetcharだったりするとは限らない注3)。例えばMS-DOSであれば,INT 21Hというサービス提供用のソフトウェア割り込みを使う。しかし単純な「Hello World」プログラムは,ほぼどんなプラットフォームでもソース・コード互換である。これを実現しているシカケが標準Cライブラリである。

 このアイデアを発展させれば,クロス・プラットフォーム開発が可能になるのもわかるだろう。例えば米Borland Software社の開発ツール「Delphi」と「Kylix」では,CLX(Component Library for Crossplatform)と呼ぶ共通のライブラリを利用できる。このレイヤでウインドウ・システムのGUI呼び出しやイベントの処理などを仮想化している。その結果として共通のソース・コードからLiunxとWindowsのプログラムを作成できる。もちろん,そのうえで言語コンパイラが互換になっていなければならない。

複雑でうっとうしい手続きを隠蔽する

 CLXは複雑な処理を隠蔽しているライブラリの例でもある。Windowsのイベント処理モデルやX Window Systemのコールバックなどをまったく意識する必要がない。このような例はオブジェクト指向言語では枚挙に暇がない。古くはMacintosh用のObject Pascal言語によるフレームワーク「MacApp」,Microsoft社の「MFC(Microsoft Foundation Class)」,Borland社製品では「VCL(Visual Component Library)」やMS-DOSベースのウインドウ「Turbo Vision」などが挙げられよう。また特に名称は付いていないがSmalltalkのウインドウ・クラス・ライブラリもその一例である。ちょっとニュアンスが違うが,ノルウェーTroll Tech社の「Qt」やGtkのようなX Window System用のウィジェット・ライブラリも,裸のXを使いやすくしているという意味では同等かもしれない。

 これらを見ればわかるように,基本的にライブラリはプログラミング言語およびその処理系と密接に関連している。“処理系に固有のもの”と言っても過言ではないくらいだ。ウインドウを一つ表示するプログラムを記述するのに,1行だけで済むレベルにまで抽象化しているものもあれば,ある程度の決まりにしたがって記述しなければならないものもある。

 いずれにしても最近のGUIベースのOSの場合,機能が豊富で複雑になるぶんAPIが複雑である。また,GUIに対応したアプリケーションの場合,OSの“決まり事”が必ずある。この決まり事はアプリケーションの本質ではない。純粋にOSが提供するAPIだけを使ってプログラミングしようとすると,決まり事を記述することにかなりの手間をとられてしまう。

「私がいつも使っているコンポーネントは,ライブラリなんですね」
「ライブラリを使えば,かなりの手間は軽減できるね」
「そういえば,複雑な約束事って,どんなことなんでしょうか」
「それは,プログラムの作りに関係してくるんだ。GUIならイベント・ドリブンとかね」

(北郷 達郎、八木 玲子)