コンピュータは部品、周辺機器などといった物理的構成要素であるハードウェアと、規則、手続き、プログラムなどといったノウハウであるソフトウェアから構成されています。ソフトウェアは用途などに応じていくつかに分類できます。また、ハードウェアとソフトウェアの中間に位置するようなものはファームウェアと呼ばれ、CPUの制御に用いるマイクロプログラムなどが該当します。
システムソフトウェアはハードを直接制御し、効率的な利用を提供したり、共通の機能を提供して開発を容易にするものです。
ハードを動かす上で基本となるソフトウェアのことです。コンピュータを直接制御し、効率を図る制御プログラム(※)、プログラムを機械語に翻訳する言語処理プロセッサ、ユーザにサービスを提供するサービスプログラムなどが含まれます。
基本ソフトウェアと応用ソフトウェアの中間に位置します。通常OSに含まれない特殊な機能をOSに代わって提供するソフトウェアです。DBMS(データベースマネジメントシステム)やソフトウェア開発支援ソフト、WEBアプリケーションサーバなどが含まれます。
応用ソフトウェアはアプリケーションソフトウェアとも呼ばれ、特定の目的に利用するために使うソフトウェアのことです。多くの人が共通して使うソフトウェアである共通応用ソフトウェアと、ある一定の業務活動内で使用する個別応用ソフトウェアがあります。
CAD、統計処理、ワープロ、表計算ソフトなどが含まれます。
経理システム、販売・在庫管理システムなどの業務用アプリケーションが含まれます。
(※)制御プログラムはカーネル、デバイスドライバ、ファイルシステムなどから構成されています。カーネルはOSのコアの部分で、スーパバイザと呼ばれることもあります。
ハードウェアを効率よく無駄のないように利用するための制御を行います。結果としてスループット、タイムアラウンドタイムの向上が実現します。ハードウェアを効果的に利用するためのプログラムを制御プログラムといい、これを指してOSということもあります。
プログラムをコンピュータが理解できる機械語に翻訳する機能を提供します。これらの機能は言語プロセッサと呼ばれるプログラムが提供し、コンパイラやインタプリタ、アセンブラなどがあります。
ユーザにハードウェアを意識させることなくシステムを利用できるようにします。UNIX、WindowsではGUIを提供します。
API(Application Program Interface)とは、プログラマーがOSの機能を利用できるようにする機能のことです。プログラムから呼び出せる関数などを提供します。
+------+ GUI +----+ API +---------+ | User |=======| OS |=======| Program | +------+ +----+ +---------+ || || ::::::::::::::::::::::::::::::::::::::: || Hard Ware +--------------+-----+-----+ | Mous/Keybord | CPU | HDD | +--------------+-----+-----+
安定してコンピュータを使うことができるように信頼性、可用性、保守性、安全性を向上させます。
ジョブとは、オペレータ(利用者)がコンピュータに仕事を依頼する単位のことで、人間から見た仕事の単位のことです。このジョブというものはバッチ処理など、一つ以上のプログラムから構成されています。コンピュータはジョブをいくつかのジョブステップという段階に分け、利用するハードウェア資源を割り当てながら実行します。最終的にスループットの向上を図ることがジョブ管理の役割です。
ジョブ管理はジョブの実行を管理する機能とハードウェア資源の割り当て・解放を行う機能に分けられます。汎用機ではJCL(Job Control Language)によりコンピュータにジョブ実行に必要な環境、手順を知らせます。
ジョブスケジューラによって必要なハードウェア資源の割り当てと順序を管理すると同時にマスタースケジューラを通してオペレータ(利用者)にジョブの実行状態を報告、およびオペレータからの指示を受け取ります。
マスタースケジューラはジョブの実行状況をオペレータに報告したり、オペレータに対する要求を表示したり、オペレータからの命令を受け付けます。これはつまりオペレータとシステム間の情報の伝達を行う仲介になっています。また、磁気ディスクのマウントなども行います。
ジョブスケジューラには4つの機能があり、機能とその役割は次の通りです。
依頼されたジョブのジョブ名、優先度、要求資源などを読み取り、優先順位をつけて待ち行列に加える
待ち行列中から優先順位が高いジョブを選び出し、要求しているハードウェア資源を割り当てた後、ジョブステップに分解し実行する
出力すべき情報を出力待ち行列に加え、ハードウェア資源の解放を行いジョブを終了する
出力待ち行列から優先順位に従って情報を出力する
CPUの処理速度と比較して、入出力装置の処理速度は非常に低速です。この速度差のためにいくらCPUでの処理が高速であっても処理効率の低下を招いてしまいます。このため、入出力装置よりも高速な磁気ディスクに一時保存することで待ち時間を短縮しています。例としては、カードリーダやプリンタなどは送受信されるデータを一時的に磁気ディスクに格納し、CPUはこの磁気ディスクを高速な入力装置としてデータのやりとりを行います。このようにして待ち時間を短縮することをスプール(Spool)処理やスプーリングといいます。
[JCL input] | ジョブ入力 +--------+ .→| Reader | | +--------+ | | ジョブ登録 | *===========* | |Input Queue| | *===========* | | ジョブ選択 +---------+ | +---------+ |Master |←:→|Initiator|←**************. |Scheduler| | +---------+ 資源割り当て | +---------+ | | ジョブ開始 | ↑ | +-----------+ | ↓ |→|(Executing)| Hard ware Resource +--------+ | +-----------+ ==================== |Tarminal| | | ジョブ終了 ↑ +--------+ | +------------+ 資源解放 | |→| Terminator |*************^ | +------------+ | | 出力情報登録 | *============* | |Output Queue| | *============* | | 出力情報登録 | +--------+ ^→| Writer | +--------+ | 出力 [Out put]
タスクはプロセスとも呼ばれ、コンピュータが処理を行う場合の単位です。ジョブとの違いは、ジョブはオペレータ側から見た処理単位であるのに対してタスクはコンピュータ側から見た処理単位であるとい点です。 タスク管理の目的はジョブを実行可能な複数のタスクに分割して実行することで、入出力待ちなどの待ち時間を極力減らし、効率的に処理を行う目的があります。
ジョブスケジューラからジョブステップを受け取ってタスクを生成し、主記憶領域や必要なレジスタなどの必要資源を割り当ててタスク待ち行列に加えます。それと同時に優先順位や主記憶領域や必要なレジスタなどを記憶するTCB(Task Control Block)という管理用データを生成し、それぞれのタスクの情報を格納します。これらのデータをコンテキスト(Context)と呼び、マルチプログラミングではこのコンテキストを切り替えることで実現しています。
待ち行列中のタスクの中から優先順位の高いタスクにCPU実行時間を割り当てます。これにより待ち状態のタスクは実行状態へ遷移(せんい)します。
割り込みが発生すると、割り込み処理ルーチンが原因を解析し、ディスパッチャに結果を渡します。割り込みにはソフトウェア上の問題が原因となる内部割込みと、入出力装置などのソフトウェア外から発せられる外部割込みに分けられます。
[内部割り込み] 入出力装置(I/O)の処理速度はCPUの処理速度と比べて非常に遅いです。そのため、入出力を行っている長い時間CPUは何も処理をしていない状態となり、無駄が生じてしまいます。この場合、CPUが休んでいる間別のプログラムのCPUを使う処理を行うことでCPUの無駄を縮小させることができます。こういった仕組みをマルチプログラミング(マルチタスク)と呼びます。(figure1)を参照してください。
また、このままですとI/Oを使用しないプログラムがCPUを占領し、他のプログラムがCPUの待ち時間を利用して処理を行うことができません。これではマルチプログラミングが成り立ちませんので、CPUを使える時間を設け、この時間を超過したら他のプログラムにCPUを割り当てます。このCPUを使える時間のことをタイムスライスといいます。
(figure1) http://ruffnex.oc.to/defolos/text1/figure/figure34.jpg
タイムシェアリングシステム(TTS)はCPU使用時間を細かく区切り、複数のタスクなどの処理を単位時間ごとに切り替えることでマルチプログラミングを行う仕組みです。各処理に同一の使用時間を割り当てて順番に処理を進めていく方法をラウンドロビン法と呼びます。
生成されたタスクは他のタスクとの順番が調整され、3つの状態を遷移しながら実行していきます。
入出力待ち、あるいは必要な資源の割り当て待ちなど、CPUを使う準備ができてない状態です。入出力待ちの場合は入出力装置から処理完了通知(入出力割込み)を受け取った場合、実行可能状態へ遷移します。
必要資源が割り当てられ、CPUの割り当てを待っている状態です。このReady状態のタスクの中から優先順位などの情報からCPU時間を割り当てるタスクが選択され、選択されたタスクはRun状態へ遷移します。のタスクの選択をディスパッチングやスケジューリングと呼びます。
CPU時間が割り当てられて、タスクが実行中の状態です。処理が終了すればタスクは消滅し、現在CPU時間が割り当てられているタスクより優先順位が高いタスクがReady状態になって実行依頼をしたときや、与えられたタイムスライスを使い切ったときにはReady状態に遷移し、タスクが入出力要求を行ったときにはWait状態へ遷移します。
(figure2) http://ruffnex.oc.to/defolos/text1/figure/figure35.jpg
マルチタスクでは、複数のタスクが同一のCPUを利用する必要があります。タスクAがRun状態のとき、新たに優先度の高いタスクBが作られたとします。この場合、タスク管理プログラムはタスクAをReady状態に遷移し、タスクBにCPU時間を割り当てます。このようにタスク管理プログラムがタスクの状態を管理することをプリエンプションといいます。WindowsやUnix/Linux、メインフレームなどのOSはこの機能を備えています。
一方、Windows3.XなどのOSは、実行中のタスクが自発的にReady状態へ戻るというノンプリエンプティブなOSでした。この方式ではトラブルなどでタスクが無限ループに突入した際にはOSに制御が戻らず、システムがハングアップしてしまいます。
処理要求のあったタスクのうち、どのタスクにどれだけのCPU使用時間を割り当てるかを決定することをディスパッチングやスケジューリングと呼びます。代表的なディスパッチング方法は次の通りです。
実行要求が出されたタスクからディスパッチングします。この場合、他のタスクは現在処理中のタスクの終了まで実行されません。
実行を待っているタスクに同一の長さのCPU使用時間(クォンタイム)を割り当てる方式です。
優先順位ごとに実行待ち行列を持ち、優先順位の高いタスクからCPU使用時間を割り当てます。この場合、後から到着したタスクであっても、優先順位が高ければ優先順位が低いタスクよりも先にCPU使用時間が割り当てられます。優先順位が低いタスクは長時間処理されない可能性もあります。
優先度ごとに実行待ち行列を持っています。初めて実行するタスクにはCPU使用時間を短く割り当てますが、優先度は高くなります。タイムスライスを使い切ると優先度を低くしてCPU使用時間を長く設定します。
現在では、ほとんどのシステムは優先順位方式とラウンドロビン方式を併用しています。優先順位に従ってディスパッチングを行い、優先順位が同じだった場合はラウンドロビン方式を適用します。
複数タスクを同時に実行する場合、タスクが同一の資源にアクセスすることがあります。このような場合、次のようなエラーが発生する恐れがあるため、排他制御を行う必要があります。
[Task 1] +-----------+ [Task 2] 1.)変数Aを読み込む←---| 変数 A |----→2.)変数Aを読み込む 3.)変数Aに3を足す | | 4.)変数Aから8引く 5.)変数Aを更新する---→| 値 50 |←----6.)変数Aを更新する +-----------+
上記のアスキーアートの例ですと、Task1の1.)の処理で読み出された変数Aを更新する前にTask2の2.)で読み出しています。さらにTask1の5.)処理で変数の値を変更した後にTask2の6.)処理で変数の値を上書きしています。これによりTask1の一連の処理は変数Aに反映されずにTask2の処理だけが反映されてしまいます。これをロストアップデートと呼びますが、この場合、Task1が1.)処理で変数Aの値を読み込んだ時点で他のタスクが変数Aを読み出しも書き込みもできないようにロックをかけて排他制御する必要があります。変数Aにロックがかかっているかどうかを他のタスクへ通知するには、セマフォと呼ばれるフラグを用います。
セマフォはロック状態を表す0と、アンロック状態を表す1で、ある資源に対するアクセスを制御する仕組みです。セマフォの0と1を操作するにはP動作とV動作で行います。P動作は資源にアクセスする際に、その資源に対するセマフォの値を読み取り、1であれば-1してロック状態にします。一方V動作は資源への更新が終わった後に、資源に対するセマフォの値を+1し、アンロック状態にします。
例として前述のアスキーアートをセマフォを用いて制御していみます。
[Task 1] +-----------+ [Task 2] 1.)【P動作】 | 変数 A | 2.)【P動作】 セマフォの値を読む | | セマフォの値を読む 0ならば待機する | 値 50 | 0になっているので待機 1ならば-1する +-----------+ ...wait... . 3.)変数Aを読み込む +-----------+ . 4.)変数Aに3を足す | セマフォ | . 5.)変数Aを更新する | 1 | . | ↓ | . 6.)【V動作】 | 0 | . セマフォの値を+1する | ↓ | 1になったので-1する | 1 | | ↓ | 7.)変数Aを読み込む | 0 | 8.)変数Aから8引く | ↓ | 9.)変数Aを更新する | 1 | +-----------+ 10.)【V動作】 セマフォの値を+1する
デッドロックとは、排他制御をするに際し、2つ以上のタスクがロックされている資源をそれぞれ必要とする場合に、それぞれのタスクがロックの解除待ちをして処理が進まなくなってしまう状態です。次の例を見てください。
[Task 1] +-----------+ [Task 2] 1.)変数Aを読み込む | 変数 A | 2.)変数Bを読み込む 3.)変数Bを読み込む | | 4.)変数Aを読み込む | 変数 B | +-----------+
この場合、Task1が変数Aを読み込み、変数Aを排他制御します。次にTask2が変数Bを読み込み、同じく排他制御します。問題となるのは次にTask1が変数Bを読み出そうとしている点です。そうすると変数BはTask2によって排他制御されていますので、Task2の処理が終わるまでTask1が必要としている変数Bは使用できません。その一方でTask2が必要としている変数AもTask1によって排他制御されているためにTask2も処理を終えることができません。結果的に2つのタスクは永久にこの状態から抜け出せなくなります。
このような状態をデッドロックといい、デッドロックを防ぐにはロックをかける順番を決めておくことが必要です。前の例ですとTask1もTask2もはじめに変数Aを読み込んでロックをかけようとし、次に変数Bを読み込もうとするようにします。このようにロックをかける順番を決めておけば、Task2はロック解除待ちとなってデッドロックは発生しません。
記憶管理は、主記憶上の限られたメモリ空間を効率よく利用するのが目的です。プログラムは必ず主記憶上にプログラム本体と利用するデータが置かれていなければなりません。現在多くのOSで実装されているマルチタスクでは、主記憶上に複数のプログラムとデータがロードされていなければマルチタスクを実現することができません。これは効率的に記憶管理を行わなければならないということです。
プログラムやデータは主記憶にロードされなければ実行することはできません。このときロードできる主記憶上の領域を物理アドレス空間と呼び、プログラムが実行に必要とする領域を論理アドレス空間と呼びます。プログラム自体が大きい場合やマルチタスクで必要な論理アドレス空間が増えた場合、物理アドレス空間が足りなくなることがあります。
こういった場合、一度に全てのプログラムを主記憶にロードせずに、主記憶に入りきらない分は補助記憶装置に格納しておき、必要なときに主記憶と補助記憶間で部分的に入れ替えることで解決します。これを仮想記憶方式と呼びます。補助記憶装置に作られた仮想的な主記憶領域を仮想アドレス空間といい、それに対して主記憶装置を実記憶と呼びます。
プログラムがロードされる主記憶アドレスに関係なく実行できることをリロケータブル(再配置可能)といいます。リロケータブルプログラムのアドレスは相対アドレスで記述されておりアドレス変換機構で実行アドレスに変換されます。
リロケータブルにも静的再配置と動的再配置があります。静的再配置はロードモジュールを相対アドレスのままロードし、プログラムが実アドレスを必要とするたび、アドレス変換機構がページテーブルを参照して実行アドレスに変換します。動的再配置ではすでに主記憶上にロードされていても再配置によってフラグメンテーションを解消することができます。
仮想アドレス空間を使用せずに主記憶上の実記憶のみを用いて記憶管理を行う方式です。管理手法には次に挙げる2つの方式があります。また、プログラムのバグなどで確保したメモリ空間が解放されず、主記憶中の利用できるアドレス空間が減少することをメモリリークといいます。
主記憶上のアドレス空間を、固定されたサイズの区画(partition)に分割し、区画単位でプログラムのロードを行います。内部断片化により無駄な空き領域が生じ、主記憶の利用効率を下げる原因となります。
プログラムの大きさに応じて区画をロードできるようにした方式です。
区画に無駄が生じることはありませんが、プログラムの入れ替えが多くなると区画と区画の間に利用されない領域が増えて効率が下がります。これを外部断片化やフラグメンテーションといいます。フラグメンテーションは定期的に空き領域を整理して連続した領域にするガベレージコレクションやコンパクションで解決します。
また、空き領域の割り当て手法には次のようなものがあります。
実行しているプログラムより優先順位の高いプログラムを実行する場合、現在実行しているプログラムを磁気ディスクに退避しておき、その主記憶領域にプログラムをロードする方式です。退避したプログラムは必要に応じて主記憶上に再ロードされます。磁気ディスクに退避させることをスワップアウトやロールアウトといい、磁気ディスクから主記憶上に戻すことをスワップインやロールインといいます。このスワップアウトとスワップインの一連の流れをスワッピングといいます。
プログラムをあらかじめセグメントと呼ばれる単位に分割し、必要なセグメントを上書きするようにロードすることで実行します。
例えば主記憶の大きさが100MBだったとしましょう。そこに120MBのプログラムを実行する場合、プログラムをセグメントA、セグメントB、セグメントCに分けます。後はセグメントAとセグメントBで実行し、途中でセグメントCに含まれる部分が必要になったらセグメントBとセグメントCを入れ替えます。セグメントAはセグメントBとCを制御できるようにしますのでBとCを入れ替えても実行できるようになります。下のアスキーアートの場合、必要な実記憶空間はセグメントAとセグメントCを足した80MBとなります。
+-----------+ | segment A | | (20MB) | +-----------+ .__________|_________. | | +-----------+ +-----------+ | segment B | | segment C | | (40MB) | | (60MB) | | | | | | | | | +-----------+ | | | | +-----------+
仮想記憶方式は主記憶のメモリ容量が足りない場合、補助記憶装置を仮想的な主記憶領域としてあつかうことで見かけ上主記憶容量を大きくする方式です。仮想アドレスと実アドレス間の変換には変換テーブルを用います。仮想記憶方式には、プログラムの使用する主記憶容量を考慮する必要がない、動的再配置がしやすいなどのメリットがあります。
仮想記憶方式では、主記憶と補助記憶を固定長の大きさに分割し、プログラムをその区画に分けてロードします。プログラムの実行に従って次の実行に必要な区画が主記憶上にない場合は、補助記憶の該当区画を主記憶の区画と入れ替えます。このとき記憶管理プログラムがプログラム上の論理アドレスをページ表を使ってその都度、物理アドレスに変換しながら処理を行います。
ページングは、プログラムを固定長ブロックに分割したページと、主記憶と補助記憶を固定長に分割したページ枠に分けます。もし主記憶にプログラムの実行に必要なページがない場合は補助記憶からページを読み込んだり、入れ替えたりします。必要なページが主記憶上にない場合におきる割り込みをページフォルトと呼び、補助記憶からページを読み出すことをページイン、ページが主記憶から補助記憶へ置かれることをページアウトと呼びます。
主記憶上に必要なページがない場合、ページフォルトが発生する
主記憶に空きページ枠がある場合は、そのページ枠に必要なページを補助記憶から読み込む
主記憶に空きページ枠がない場合、補助記憶にページを退避させて空きページ枠を作り、そこへ必要なページを読み込む
最初に入ったものを最初に出します。つまり、ロードされた時間が最も古いものを入れ替え対象とします。キューのデータ構造と同じです。
最後に入ったものを初めに出します。最後にロードされたものを置き換え対象とします。スタックのデータ構造と同じです。
参照回数の最も少ないものを置き換え対象とします。
最後に参照された時間が最も古い物を置き換え対象とします。LFUとの混同に注意しましょう。
ページングの弱点として、スラッシングが発生する可能性があるという点があります。スラッシングとはページフォルトが頻発し、ページの置き換えばかりに時間が使われて、処理効率が極端に低くなる現象のことです。
補助記憶装置のアクセス時間は主記憶のアクセス時間に比べ、とても低速です。それ故に、頻繁に補助記憶装置と主記憶間でデータのやり取りが行われると処理時間のほとんどを補助記憶装置のアクセスが占めることになってしまいます。
多くの利用者が同時に使用する汎用コンピュータでは、運用をしっかりと管理し、全体のパフォーマンスを維持する必要があります。運用管理プログラムはオペレータ(利用者)に対して稼動状況の報告やコマンドの受付を行って運用の手助けをします。
また、不正利用がないように利用権限やファイルのアクセス権限を監視し、アクセスログを記録するセキュリティ管理も行います。
障害発生時にシステム全体の停止を防ぎ、復旧を迅速に行うためのOSの機能です。コンピュータ構成要素の各要素の障害監視を行い、障害や異常を監視し、障害状況の記録やオペレータへの報告を行います。障害管理プログラムは自動的に訂正を行ったり、障害が発生している箇所を切り離して運用を続行するバックアップ機能を持っています。
データ管理プログラムからの指示に従い、入出力装置と主記憶装置とのデータのやり取りを制御し、円滑にやり取りを行うようにします。入出力の受付や入出力の実行順序の管理、入出力エラーの検出と回復などを行います。
コンピュータがネットワークを通じて他の端末に接続されている場合には通信管理が必要になります。通信管理プログラムは通信経路とプロトコルを選択し、データ送受信の制御を行います。また、伝送エラーの検出や回復処理を行います。通信管理プログラムによってオペレータはプロトコルや機種の違いを意識することなく通信を行うことができます。