プロセス

はじめに

第3章はじめに

このビデオでは、この章で取り上げるコンテンツの概要を説明します。


学習目標
この章の終わりまでに、次のことができるようになります。

プロセスとそれに関連付けられたリソースを説明できます。
initプロセスの役割を説明できます。
プロセス、プログラム、スレッドの違いがわかります。
プロセスの属性、パーミッション、状態を理解し、制限を管理する方法を理解できます。
ユーザー モードとカーネル モードでの実行の違いを説明できます。
デーモン プロセスを説明できます。
新しいプロセスがどのようにフォーク（生成）されるかを理解できます。
niceとreniceを使用して、優先順位を設定および変更できます。
共有ライブラリと静的ライブラリの使用方法を理解できます。


プロセス

プログラム、プロセス、スレッド
プログラムとは、一連の命令と、命令を実行する時に使用する内部データのことを言います。また、プログラムは外部データを使用する場合もあります。内部データには、ユーザー プロンプトの表示に使用される、プログラム内のテキスト文字列が含まれる場合があります。外部データには、データベースからのデータを含む場合があります。ls、cat、rmなどの多くのユーザー コマンドは、オペレーティング システムのカーネルの外部にあるプログラムやシュルです（つまり、ディスク上にある独自の実行可能プログラムです）。

プロセスとは、実行中のプログラム、環境、開いているファイル、シグナル ハンドラなどの関連リソースを指しています。同じプログラムが同時に複数回実行されている場合は、複数のプロセスが生成されます。

それに加えて、2つ以上のタスクまたは実行スレッドは、全メモリ領域（または特定のメモリ領域）や開いているファイルなど、さまざまなリソースを共有できます。環境がすべて共有されているものは、マルチスレッド プロセスと言います。

他のオペレーティング システムでは、ヘビー ウェイト プロセスとライト ウェイト プロセスの間に大きな違いがあるかもしれません。厳密に言えば、ヘビー ウェイト プロセスには、複数のライト ウェイト プロセスが含まれる場合もあれば、そのうちの1つだけが含まれる場合もあります。

Linuxでは、状況がはまったく違います。実行する各スレッドは個別に考慮されます。ヘビー ウェイト プロセスとライト ウェイト プロセスの違いは、リソースの共有と、実行スレッド間のコンテキストの切り替えの速度だけです。

他のオペレーティング システムとは異なり、Linuxは常にプロセスの生成、破棄、切り替えを非常に高速に実行しています。そのため、マルチスレッド アプリケーションに採用されたモデルは、マルチ プロセスに似ています。各スレッドは、独立したプロセスであるかのように、個別に普通にスケジュールされます。
これは、異なるプロセス間でスケジューリングを行うだけでなく、プロセスのスレッド間でも個別のスケジューリングを行うような、複雑なスケジューリングを増やす代わりに行われます。

同時に、LinuxはPOSIXおよびマルチスレッド プロセスの他の標準仕様も尊重します。たとえば、各スレッドは、個別のスレッドID（内部ではプロセスIDと呼ばれます）を返す一方で、同じプロセスID（内部ではスレッド グループIDと呼ばれます）も返します。これは開発者を混乱させる可能性がありますが、管理者には見えないので問題はないはずです。


プロセスとは？
プロセスは、実行中のプログラムのインスタンスです。実行中やスリープ中など、さまざまな状態になる場合があります。すべてのプロセスには、pid（プロセスID）、ppid（親プロセスID）、pgid（プロセス グループID）があります。さらに、すべてのプロセスは、プログラム コード、データ、変数、ファイル記述子、および環境を持っています。

initは通常、システム上で実行される最初のユーザー プロセスであり、カーネルから直接開始されたものを除いて、その後システム上で実行されるすべてのプロセスの祖先となります（psリストの名前の周りに [] で表示されます）。

子プロセスの前に親プロセスが終了した場合、子プロセスの ppid は1に設定されます。つまり、子プロセスの新しい親はinitプロセスになります。（注：systemdを使用する最近の Linuxシステムでは、ppidが2になります。kthreaddとして知られる内部カーネル スレッドが、孤児プロセスの親の役割をinitから引き継ぐからです。）

親プロセスよりも前に（通常でも異常でも）終了し、親プロセスがその終了を待たずかつ終了コードを調べることもしない子プロセスは、ゾンビ（または無効）プロセスと呼ばれます。このゾンビ プロセスは、自分のすべてのリソースの解放と終了ステータスを伝えるためだけに残っています。initプロセスの機能の1つは、ゾンビ プロセスを確認しきちんと終わらせることです。したがって、それは時々ゾンビ キラー、またはもっと恐ろしい表現で、child reaper（子供の死神）などと言われます。

プロセスは、完全にプリエンプションするスケジューリングによって制御されています。プロセスをプリエンプションする権限を持つのはカーネルのみです。プロセス同士ではできません。

過去のいろいろな経緯から、PIDの最大値は16ビット数、つまり32768に制限されています。/proc/sys/kernel/pid_maxを変更することでこの値を変更することができます。大規模なサーバーでは、デフォルトの最大値では足りない場合があるためです。プロセスが生成され続けて行くと、最終的にその数はpid_maxになります。そうすると再びPID = 300から割り当てられます。


プロセス属性
すべてのプロセスには特定の属性があります。

実行中のプログラム
コンテキスト（状態）
パーミッション
関連リソース

すべてのプロセスが何らかのプログラムを実行しています。プロセスは、CPUレジスタの状態、プログラム内で実行されている箇所、プロセスのメモリの内容、およびその他の情報を補足することにより、いつでも自身のスナップショットを取ることができます。このスナップショットがプロセスのコンテキストです。

CPU時間を他のユーザーと共有するときに（または、ユーザーが要求やデータの到着を待つなどの条件が満たされるまでスリープ状態になるときに）、プロセスをスケジュールすることができます。コンテキストの切り替えを行うカーネルには、プロセスをスワップ アウトするときにコンテキスト全体を格納し、実行を再開したときに復元できることが求められます。

すべてのプロセスには、実行のために呼び出したユーザーに基づいたパーミッションがあります。また、プログラム ファイルの所有者に基づいたパーミッションもあります。「s」実行ビットでマークされたプログラムには、「実効」ユーザーIDとは異なる「実」ユーザーIDがあります。これらのプログラムは、setuidプログラムと呼ばれます。これらはプログラムを所有するユーザーのユーザーIDで実行されます。これに対して非setuidプログラムは、プログラムを開始したユーザーのパーミッションの範囲内で実行されます。ただし、rootが所有するsetuidプログラムの実行は、セキュリティ上の問題になる可能性があります。

setuidプログラムの例として、passwdコマンドがあります。これはすべてのユーザーが実行できます。ユーザーがこのプログラムを実行すると、プロセスはroot権限で実行され、ユーザーのパスワードが保持されている書き込み制限があるファイル/etc/passwdと/etc/shadowを更新できるようになります。

すべてのプロセスは、割り当てられたメモリ、ファイル ハンドラなどのリソースを持っています。


プロセス リソースの分離
プロセスが開始されると、そのプロセスは他のプロセスから保護するために独自のユーザー空間を持ちます。これにより、セキュリティが向上し、安定性が向上します。

プロセスはハードウェアに直接アクセスできません。ハードウェアはカーネルによって管理されるため、プロセスはシステムコールを使用して間接的にハードウェアにアクセスします。システムコールは、アプリケーションとカーネルの間の基本的なインターフェイスです。


ulimitでプロセスを制御する

ulimit は組み込みbashコマンドで、シェルで実行されるプロセスに関連する多くのリソース制限を表示または再設定します。以下のスクリーンショットで、ulimit で -a 引数を指定して 得られる内容を確認できます。

ulimit -a コマンドとその出力のスクリーンショット

システム管理者は、以下の理由で、これらの値の一部を変更する場合があります。

個々のユーザーやプロセスが、メモリ、CPU時間、システム上のプロセスの最大数などのシステム リソースを使い果たすことがないように、機能を制限するため。
プロセスがリソースの限界に達しないように機能を拡張するため。たとえば、多くのクライアントを処理するサーバーでは、デフォルトの1024個のファイルを開くと、サーバーの作業を実行できなくなる場合があります。

制限には次の2種類があります。

ハード
ユーザーが引き上げることができるリソース制限の最大値。rootユーザーのみが設定できます。
$ ulimit -H -n
4096

ソフト
現在の制限値。一般ユーザーが変更できますが、ハードの制限を超えることはできません。
$ ulimit -S -n
1024

以下を実行することにより、特定の制限値を設定できます。

$ ulimit [options] [limit]

例えば

$ ulimit -n 1600

同時に開くことができるファイルの最大数が1600になります。

変更は現在のシェルにのみ影響することに注意してください。ログインしているすべてのユーザーに有効な変更を加えるには、/etc/security/limits.conf（とても良いドキュメントを内包しています）を変更してから再起動する必要があります。


プロセスの状態
プロセスの状態は数種類あります。スケジューラはすべてのプロセスを管理します。プロセスの状態は、プロセス リストによって知るとができます。

主なプロセスの状態については、各ボックスをクリックして展開して見てください。

主なプロセス状態

Running
プロセスは現在、CPUまたはCPUコアで実行中か、実行キューにいて新しいタイム スライスの割り当てを待っています。スケジューラがCPUを占有するべきと判断した場合、または別のCPUがアイドル状態になり、スケジューラがそのCPUにプロセスを移行した場合、実行を再開します。

Sleeping（すなわち Waiting）
プロセスは、リクエスト（通常は I/O）が実行されるのを待っている状態です。リクエストが完了するまで待ち続けます。リクエストが完了すると、カーネルはプロセスを起動し、実行キューに戻します。スケジューラはCPUのタイム スライスを与えます。

Stopped
プロセスは中断されています。この状態は、プログラマが実行中のプログラムのメモリ、CPUレジスタ、フラグ、またはその他の属性を調べたい場合によく発生します。これが完了すると、プロセスを再開できます。この状態には、通常、プロセスがデバッガの下で実行されているとき、またはユーザーがCtrl-Zを押したときになります。

Zombie（ゾンビ）
プロセスは終了時にこの状態になります。そして、他のプロセス（通常は親）がその終了状態について問い合わせをしない、すなわち刈り取りをしないことがあります。このようなプロセスは、存在しないプロセスとも呼ばれます。ゾンビ プロセスは、終了状態とプロセス テーブル内のエントリを除き、すべてのリソースを解放しています。プロセスの親が停止すると、そのプロセスはinit（PID = 1）またはkthreadd（PID = 2）の子供になります。


実行モード
いつでも、プロセス（またはマルチスレッド プロセスの特定のスレッド）は、ユーザー モードまたはシステム モードで実行できます。カーネル開発者は通常、システム モードをカーネル モードと呼びます。

実行できる命令はモードによって異なり、ソフトウェアではなくハードウェア レベルで実行されます。

モードはシステムの状態ではありません。これはプロセッサの状態です。マルチコアまたはマルチCPUシステムでは、各ユニットが個別に独自の状態になることができます。

Intelの用語では、ユーザー モードはリング3と呼ばれ、システム モードはリング0と呼ばれます。


ユーザー モード
システムコールを実行する場合を除き、プロセスはユーザー モードで実行されます。ユーザー モードはカーネル モードよりも権限が低くなります。

プロセスが開始されると、そのプロセスは他のプロセスから保護するために独自のユーザー空間を持ちます。これにより、セキュリティが向上し、安定性が向上します。これは、プロセス リソースの分離と呼ばれることもあります。

ユーザー モードで実行する各プロセスには独自のメモリ空間があり、その一部は他のプロセスと共有できます。共有メモリ セグメントを除き、ユーザー プロセスは他のプロセスのメモリ空間の読み書きはできません。

rootユーザーによって実行される、またはsetuidプログラムとして実行されるプロセスも、ユーザー モードで実行されます。システムコールにジャンプする場合を除き、ハードウェアにアクセスする機能は限られています。

図　システムコール


カーネル（システム）モード
カーネル（システム）モードでは、CPUは、周辺機器、メモリ、ディスクなど、システム上のすべてのハードウェアに完全にアクセスできます。アプリケーションがこれらのリソースにアクセスする必要がある場合、システムコールを発行する必要があります。これにより、ユーザー モードからカーネル モードへのコンテキスト切り替えが発生します。ファイルの読み取りや書き込み、新しいプロセスの生成などを行う場合は、この手順に従う必要があります。

アプリケーション コードはカーネル モードで実行されることはなく、カーネル コードであるシステムコールのみが実行されます。システムコールが終了すると戻り値が生成され、プロセスは逆コンテキスト スイッチでユーザー モードに戻ります。

ハードウェア割り込みを処理したり、システムのスケジューリング ルーチンやその他の管理タスクを実行したりするときなど、プロセスとは関係なくシステムがカーネル モードにある場合もあります。


デーモン
デーモン プロセスは、ユーザーにシステムの特定サービスを提供することを唯一の目的とする、バックグラウンド プロセスです。

デーモンは、必要なときにのみ動作するため非常に効率的です。
多くのデーモンはブート時に開始されます。
デーモンの名前の多くは（常にではありませんが）最後にdが付きます。
例えば、httpdやsystemd-udevdがあります。
デーモンは、外部イベント（systemd-udevd）や経過時間（crond）の影響を受ける場合があります。
通常、デーモンには制御用端末や標準入出力デバイスはありません。
デーモンは、より優れたセキュリティ制御を提供する場合があります。
SysVinitを使用すると、/etc/init.dディレクトリ内のスクリプトがさまざまなシステム デーモンを起動します。/etc/init.d/functionsファイルで定義されたdaemonという名前のシェル関数が、これらのスクリプトを引数としてコマンドを呼び出します。


プロセスの生成
通常のLinuxシステムは常に新しいプロセスを生成しています。これはforkとも呼ばれます。元の親プロセスは実行を続けながら、新しい子プロセスが開始されます。

親プロセスのプロセスIDはそのままで、子プロセスに新しいプロセスIDが割り振られ、親プロセスに通知されます。多くの場合、forkで新しく生成された子プロセスではexecを発行し、実行するイメージに置き換えて実行します。forkとexecという用語は頻繁に使用され、人々は時々それを1つの単語のように使います。

古いUNIXシステムは、spawnと呼ばれるプログラムをよく使用しました。forkやexecと多くの点で似ていますが、詳細が異なります。これはPOSIX標準の一部でもLinuxの一部でもありません。

新しいプロセスがどのように開始されるかを知る例としては、多くのクライアントを処理するウェブ サーバーが良いでしょう。ウェブ サーバーは、クライアントとの新しい接続が確立されるたびに新しいプロセスを起動します。一方、同じプロセスの一部として新しいスレッドのみを開始する場合もあります。Linuxでは、各メカニズムはほぼ同じ時間・同じ量のリソースを使用するため、完全なプロセスを生成する場合と新しいスレッドを生成するという点では、メモリ管理以外は、技術レベルでそれほど大きな違いはありません。

別の例として、initプロセスがsshd initスクリプトを実行するとsshdデーモンが開始されます。このsshd initスクリプトはsshdデーモンの起動を担当します。このデーモン プロセスは、リモート ユーザーからのsshリクエストを受け取ります。

リクエストが受信されると、sshdはリクエスト処理のために自身の新しいコピーを生成します。各リモート ユーザーは自分用のsshdデーモンのコピーと対話して、リモート ログインを行います。sshdプロセスはログイン プログラムを起動して、リモート ユーザーを認証します。認証が成功すると、ログイン プロセスはシェル（bash）からforkしてユーザー コマンドなどを処理します。

内部カーネル プロセスは、バッファがディスクに確実に書き込みできるようにする、さまざまなCPUの負荷のバランスを均等にする、デバイス ドライバがキューに入れた作業を処理する、などのメンテナンス作業を処理します。これらのプロセスは、システムが実行されている限り実行され、実行されない時はスリープします。

外部プロセスは、通常のアプリケーションのようにユーザー空間で実行されます。ただし、カーネルが開始したプロセスです。これは非常にまれなケースであり、通常はすぐ終了します。

どのプロセスがこの性質を持っているかは、次のコマンドを実行すると簡単にわかります。

$ ps -elf

システム上のすべてのプロセスを、親プロセスIDも表示するように一覧表示すると、それらはPPID = 2になっており、kthreaddであることを指しています。kthreaddはプロセスを生成する内部カーネル スレッドです。 カーネル スレッドの名前は [ksoftirqd/0] のように角括弧でカプセル化されて表示されます。


コマンド シェルでのプロセスの生成
ユーザーがbashなどのコマンド シェル インタープリタでコマンドを実行するとどうなると思いますか？

新しいプロセスが生成されます（ユーザーのログイン シェルから分岐します）。
waitシステムコールは、親シェル プロセスをスリープ状態にします。
コマンドは、execシステムコールによって子プロセスの空間にロードされます。つまり、子プロセスのメモリ空間にあるbashプログラムをコマンド コードに置き換えます。
コマンドの実行が完了したら、子プロセスはexitシステムコールにより停止します。
親シェルは、子プロセスの終了によって再起動され、新しいシェル プロンプトの発行に進みます。
そして、親シェルは、ユーザーからの次のコマンド リクエストを待つというサイクルが繰り返されます。
バックグラウンド処理のコマンドが発行された場合（コマンド ラインの最後にアンパサンド「＆」をつけて発行します）、親シェルはwaitリクエストをスキップして、新しいシェル プロンプトをすぐに発行でき、バックグラウンド プロセスを並行して実行できます。それ以外のフォアグラウンドのリクエストに対しては、親シェルは、子プロセスが終了するかシグナルによって停止するまで待つことになります。

一部のシェル コマンド（echoやkillなど）はシェル自身に組み込まれた機能であり、プログラム ファイルの読み込みはありません。これらのコマンドに対して、forkやexecは発行されません。


niceを使用した優先順位の設定
niceとreniceコマンドを使用して、プロセスの優先順位を制御できます。UNIXの初期の頃から、niceプロセスは優先順位を他のプロセスより下げるために使われてきました。したがって、niceの値が高いほど優先度は低くなります。

nice値の範囲は、-20（最高の優先順位）から+19（最低の優先順位）までです。niceの実行方法は次のとおりです。

$ nice -n 5 command [ARGS]

これにより、commandのnice値が5上がります。 これは以下と同じです。

$ nice -5 command [ARGS]

niceコマンドでnice値を指定しないと、デフォルトとしてnice値は10加算されます。引数を指定しない場合は、現在のnice値が報告されます。例：

$ nice
0

$ nice cat &
[1] 24908

$ ps -l
F S UID   PID  PPID C PRI NI ADDR SZ WCHAN  TTY       TIME CMD
0 S 500  4670  4603 0 80   0 - 16618 wait   pts/0 00:00:00 bash
0 S 500 24855  4670 0 80   0 - 16560 wait   pts/0 00:00:00 bash
0 T 500 24908 24855 0 90  10 - 14738 signal pts/0 00:00:00 cat
0 R 500 24909 24855 0 80   0 - 15887 -      pts/0 00:00:00 ps

プロセスのnice値を上げても、実行されないわけではありません。競合するものが他にない場合は、すべてのCPU時間を取得することもあります。

-20〜19の範囲外の大きな増減の値を指定すると、範囲外の値は切り捨てられます。


nice値の変更
reniceは、既に実行しているプロセスのnice値の増減に使用されます。基本的に、その場でnice値を変更できます。

$ renice --help

Usage:
 renice [-n] [-p|--pid] <pid>...
 renice [-n] -g|--pgrp <pgid>...
 renice [-n] -u|--ユーザー <ユーザー>...

pid 20003のnice値を5上げます。

$ renice +5 -p 20003

デフォルトでは、スーパーユーザーだけがnice値を下げることができます。これは、優先度を上げることです。ただし、/etc/security/limits.confを編集すれば、一般のユーザーでも所定の範囲内でnice値を下げることができます。

非特権ユーザーがnice値を上げた後では、スーパーユーザーだけがそれを下げることができます。同時に複数のプロセスで実行できますし、他にもいくつかのオプションがあるので、man reniceを参照してください。


デモ：reniceを使用して優先順位を設定する

このビデオでは、プロセスのnice値や優先度を確認する方法、およびreniceコマンドを使用して実行中にnice値を変更する方法を示します。


静的ライブラリと共有ライブラリ
プログラムはライブラリ コードで構築されています。ライブラリは複数の目的のために開発され、多くのコンテキストで使用および再使用しています。

クリックして各カードを反転し、2種類のライブラリを確認します。

静的ライブラリ
ライブラリ関数のコードはコンパイル時にプログラムに挿入されます。その後で、ライブラリが更新されても変更されません。

共有ライブラリ
ライブラリ関数のコードは実行時にプログラムに読み込まれます。ライブラリが後で変更された場合、実行中のプログラムは新しいライブラリを使って実行します。 

共有ライブラリは、多くのアプリケーションが同時に使用できるため効率的です。メモリ使用量、実行可能サイズ、アプリケーションのロード時間が削減されます。

共有ライブラリは、ダイナミック リンク ライブラリ（DLL）とも呼ばれます。


共有ライブラリのバージョン
共有ライブラリは慎重にバージョン管理する必要があります。ライブラリに大きな変更があり、プログラムがそれに対応できていない場合、深刻な問題の発生が予想されるからです。これは、DLL地獄（DLL Hell)と呼ばれることもあります。

それを避けるために、プログラムはシステム上の最新バージョンではなく、特定のメジャーなライブラリ バージョンを要求できます。しかしながら、通常、大抵のプログラムは常に最新のマイナー バージョンを使用するでしょう。

一部のアプリケーション プロバイダは、これらの問題を回避するために、プログラムにバンドルされている静的ライブラリを使用します。ただしこの場合、ライブラリが改善またはバグやセキュリティホールの修正がされても、タイムリーにアプリケーションに反映されないことがあります。

共有ライブラリの拡張子は.soです。通常、フルネームはlibc.so.Nのような形で表されます。Nはメジャー バージョン番号を示します。

Linuxでは、共有ライブラリは慎重にバージョン管理されています。例えば、

c7:/usr/lib64>ls -lF libgdbm.so*
lrwxrwxrwx 1 root root    16 Apr  9 2015 libgdbm.so -> libgdbm.so.4.0.0*
lrwxrwxrwx 1 root root    16 Apr  9 2015 libgdbm.so.4 -> libgdbm.so.4.0.0*
-rwxr-xr-x 1 root root 36720 Jan 24 2014 libgdbm.so.4.0.0*
c7:/usr/lib64>

そのため、プログラムがlibgdmだけを要求する場合はlibgdm.soを取得し、それ以外の場合は特定のメジャー バージョンとマイナー バージョンを取得します。


共有ライブラリの検索
共有ライブラリを使用するプログラムは、実行時にそれらを見つける必要があります。

lddを使用して、実行可能なファイルが要求する共有ライブラリが何かを確認できます。ライブラリのsonameとそれが実際に何のファイルを指すかを示します。

ldd /usr/bin/vi コマンドとその出力のスクリーンショット

ldconfigは通常、/etc/ld.so.confを使用してブート時に実行されます（それ以外にもいつでも実行できます）。/etc/ld.so.confには、共有ライブラリを検索するためのディレクトリのリストがあります。ldconfigはルート権限で実行する必要があります。共有ライブラリは、安定していて有用な場合のみシステム ディレクトリに格納します。

リンカーは、ldconfigによって構築されたデータベースを検索する以外に、PATH変数のようにコロンで区切られた、ディレクトリのリストの環境変数LD_LIBRARY_PATHで指定されたディレクトリを最初に検索します。たとえば、次のようにできます。

$ LD_LIBRARY_PATH=$HOME/foo/lib ; foo [args]

または

$ LD_LIBRARY_PATH=$HOME/foo/lib foo [args]


演習

課題 3.1: ulimitでプロセスを制御する

🚩
以下のPDFドキュメントに埋め込まれた外部URLにアクセスする場合は、常に右クリックして新しいタブまたはウィンドウで開いてください。直接クリックしてURLを開こうとすると、コース ウィンドウ／タブが閉じます。

【【これ以降は橋本さんの訳を参照】】

Please do:

$ help ulimit

and read /etc/security/ limits.conf before doing the following steps.

1.  Start a new shell by typing bash (or opening a new terminal) so that your changes are only effective in the new shell.View the current limit on the number of open files and explicitly view the hard and soft limits.

2.  Set the limit to the hard limit value and verify if it worked.

3.  Set the hard limit to 2048 and verify it worked.

4.  Try to set the limit back to the previous value. Did it work?

Solution 3.1

1.$ bash
$ ulimit -n
1024
$ ulimit -S -n
1024
$ ulimit -H -n
4096

2.$ ulimit -n hard
$ ulimit -n
4096

3.$ ulimit -n 2048
$ ulimit -n
2048

4.$ ulimit -n 4096
bash: ulimit: open files: cannot modify limit: Operation not permitted
$ ulimit -n
2048

You can’t do this anymore!
Note that if we had chosen a different limit, such as stack size (-s) we could raise back up again as the hard limit is unlimited.


課題 3.2: System VのIPCの動作を確認する

🚩
以下のPDFドキュメントに埋め込まれた外部URLにアクセスする場合は、常に右クリックして新しいタブまたはウィンドウで開いてください。直接クリックしてURLを開こうとすると、コース ウィンドウ／タブが閉じます。

Exercise 3.2: Examining System V IPC Activity

System V IPCis a rather old method ofInterProcessCommunication that dates back to the early days ofUNIX. It involvesthree mechanisms:

1.Shared メモリ Segments
2.Semaphores
3.Message Queues

More modern programs tend to use POSIX IPC methods for all three of these mechanisms, but there are still plenty ofSystemV IPCapplications found in the wild.
To get an overall summary of System V IPC activity on your system, do:

$ ipcs
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x01114703 0          root       600        1000       6
0x00000000 98305      coop       600        4194304    2          dest
0x00000000 196610     coop       600        4194304    2          dest
0x00000000 23068675   coop       700        1138176    2          dest
0x00000000 23101444   coop       600        393216     2          dest
0x00000000 23134213   coop       600        524288     2          dest
0x00000000 24051718   coop       600        393216     2          dest
0x00000000 23756807   coop       600        524288     2          dest
0x00000000 24018952   coop       600        67108864   2          dest
0x00000000 23363593   coop       700        95408      2          dest
0x00000000 1441811    coop       600        2097152    2          dest
------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0x00000000 98304      apache     600        1
0x00000000 131073     apache     600        1
0x00000000 163842     apache     600        1
0x00000000 196611     apache     600        1
0x00000000 229380     apache     600        1

Note almost all of the currently running shared memory segments have a key of0(also known asIPC_PRIVATE) which meansthey are only shared between processes in a parent/child relationship.  Furthermore, all but one are marked for destructionwhen there are no further attachments.

One can gain further information about the processes that have created the segments and last attached to them with:

$ ipcs -p
------ Message Queues PIDs --------
msqid      owner      lspid      lrpid
------ Shared Memory Creator/Last-op PIDs --------
shmid      owner      cpid       lpid
0          root       1023       1023
98305      coop       2265       18780
196610     coop       2138       18775
23068675   coop       989        1663
23101444   coop       989        1663
23134213   coop       989        1663
24051718   coop       20573      1663
23756807   coop       10735      1663
24018952   coop       17875      1663
23363593   coop       989        1663
1441811    coop       2048       20573

Thus, by doing:

$ ps aux |grep -e 20573 -e 2048
coop      2048  5.3  3.7 1922996 305660 ?      Rl   Oct27  77:07 /usr/bin/gnome-shell
coop     20573  1.9  1.7 807944 141688 ?       Sl   09:56   0:01 /usr/lib64/thunderbird/thunderbird
coop     20710  0.0  0.0 112652  2312 pts/0    S+   09:57   0:00 grep --color=auto -e 20573 -e 2048

we see thunderbirdis using a shared memory segment created bygnome-shell.

Perform these steps on your system and identify the various resources being used and by who. Are there any potentialleaks(shared resources no longer being used by any active processes) on the system? For example, doing:

$ ipcs
....
----- Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
....
0x00000000 622601     coop       600        2097152    2          dest
0x0000001a 13303818   coop       666        8196       0
....

shows a shared memory segment with no attachments and not marked for destruction.  Thus it might persist forever, leakingmemory if no subsequent process attaches to it.


知識チェック

「第3章 - プロセス」を完遂しました。おめでとうございます。このクイズに答えて、これまでに学んだ概念の理解度をチェックしてください。

クイズ開始

問題 3.1
オープンするファイルの最大数を2048に変更するコマンドはどれですか？

A. nice -n 2048
B. ulimit -n 2048
C. ls -n 2048

問題 3.2
PID = 444のプロセスの優先度を5上げるコマンドはどれですか？ 答えをすべて選んでください。

A. renice 5 444
B. renice +5 444
C. nice -5 444
D. nice +5 444

問題 3.3
ゾンビ状態のプロセスとは、どのようなプロセスでしょうか？

A. スリープしており、リクエストが完了するのを待っているプロセス
B. おそらくデバッガがトレースしているために停止しているプロセス
C. 終了したけれど、他のプロセスがその終了状態についてまだ問い合わせていないプロセス
D. 親プロセスが停止したけれど、まだPID = 1になっていないため、孤立しているプロセス


