プロセス間通信
OSには複数プロセス間で、動作の指示や動作完了の通知などの連携が必要になる。
シグナルによる通信
プロセス間で非同期イベントの発生を伝えるための方法。
プログラマは、「シグナルハンドラ」という処理ルーチンをプロセスに設定できる。
→シグナルハンドラが設定されていないプロセスに関しては、シグナルのデフォルトの処理が行われる。
シグナルハンドラは、実行中の処理に割り込んで仕事をするので、実行中の処理に副作用が起こる可能性があることに注意する。
共有メモリによる通信
共有メモリと呼ばれる、どのプロセスからもアクセス可能なメモリ領域のデータを、プロセスの仮想アドレス空間に読み出す(またはその逆)ことで、プロセス間での通信を実現している
メリット
- データの転送は、物理的には1つの領域への書き込み&読み出しで行われるため、メモリの無駄がない。
- プロセス固有のメモリにアクセスする必要がないので、大量のデータであっても高速にやり取りできる。
デメリット
- 共有をおこなう各プロセスは、同じ計算機上で動作しないといけない。(プロセスのメモリ空間と共有メモリの間のmappingがおこなれるから)
パイプによる通信
UNIX系のOSに実装されている通信方法で、「複数のプログラムの入出力をつなぐ」仕組み。(linuxで「|」でつなぐやつですね、これは僕でも知ってました笑)
パイプの入出力を、それぞれ役割分担して複数のプロセスが持つことで「FIFO(first in first out)」のストリームを共有し、協調的な動作を行う。(「書き込んだ順番で読み出す」ようにしている!)
ソケットによる通信
複数プロセス間での通信をおこなう仕組み。遠隔マシン上のプロセス間通信の標準的方法となっている。
どのソケットを利用するかは、アプリケーションの要件に合わせて決定。
- TCP / IP プロトコル
FIFOの動作が保証される。
- UDP プロトコル
FIFOが保証されない。また、データの到達確認等を行わないので、高速にデータをやりとりできるが、欠落する可能性もある。
競合状態と相互排他
複数のプロセスが資源を共有して処理をすすめるとき、その共有資源が不整合を起こさないように制御する機能がOSには必要になる。
競合状態
2つまたはそれ以上のプロセスが、共有データを読み書きしているとき、最終結果がプロセスの切り替えや順序に依存してしまう状態。
相互排他
共有資源を「1つのプロセスが独占」して利用する権利をもたせるための機能。
きわどい領域
共有資源にアクセスし、競合を起こす可能性があるプログラムの部分を「きわどい領域」という。
→きわどい領域に入って処理ができるのは1つのプロセスのみ、という実装をすれば相互排他を実現できる。
ビジーウェイト
共通の「ロック変数」を準備する。
きわどい領域に入る前に、ロック変数をロック状態にしてから処理に入る。(他のプロセスは、逐次ロック変数を参照して、解除されていないかを確認し続ける。これが「ビジー」の由来?)
きわどい領域を出たら、ロック状態を解除する。
セマフォ
あるプロセスがきわどい領域に入るときに、他のプロセスが存在する場合
→他のプロセスを動かすには、当該プロセスを待ち状態にすればよい。
セマフォには、downとupの2種類のメソッドがある。
down
セマフォの値が0より大きいかを調べる。
0より大きいとき、値を1減らして次の処理を継続する。
0ならば、値を減らす前にプロセスを待ち状態にして、スリープさせる。
up
セマフォの値を1増加させる。
このとき、1つ以上のプロセスがスリープしていれば乱数などでどれか1つ選んで、スリープを解除する。(ウェイクアップ)
すなわち、down操作が継続される。
モニタ
特別に定義された関数、変数データ構造の集合。
モニタとして定義された関数は、「1つのプロセスしか」実行することができない。
プログラマは、きわどい領域にあたる関数をモニタとして定義して実装する。
→プログラマがロックとアンロックを明示的に記述しなければならないときに比べると、楽だしミスが生じにくい。
複数プロセスの問題
プロデューサ・コンシューマー問題
「プロデューサー(生産者)」と「コンシューマー(消費者)」の2プロセスにおいての問題。
- それぞれ固定長のバッファを固定メモリとして持つ
- プロデューサーはデータを生成し、バッファに追加する
- コンシューマーは、バッファからデータを取り出し、バッファ城のデータを1つずつ順に消去していく
↓
- プロデューサーは、バッファが全て使われた状態の時、データの生成を中止する(スリープ)
- コンシューマーは、バッファが空のとき、データの取り出しを中止する(スリープ)
- プロデューサーがデータを追加したとき、コンシューマーがスリープしているなら、ウェイクアップさせる。
この問題を解決する方法は、「カウンティングセマフォ」を利用する方法。(準備中)
リーダ・ライタ問題
複数プロセスの並列性に関する例。
「メモリからデータを読み出すプロセス(リーダ)」と「メモリにデータを書き込むプロセス(ライタ)」が混在しているとき、
- 複数のリーダが、同時にデータを読み出すことはできる
- あるライタがデータを書き込んでいる最中は、更新途中のデータが消えないようにリーダは読み出しができないようにする
↓
ライタは、データの書き込みに際して、ロックとアンロックをする必要がある。
リーダは最初のリーダのみが読み出し時にロックされる。
2つ目以降のリーダは、最初のリーダがすでにロックされているのでロックしない、という実装ができる