第 3 回 (2006.04.28) -- プロセス,ジョブ

その前に… 習熟度別システム分け

unix cui に対する学習の「前準備」が済んだので, この授業辺りから,学生の習熟度別に使用する環境を指定する.
各学生は自分の能力とやる気を自己判断し, 以下の選択肢のうちからみずからに適した環境を選択し, その環境で授業を受講せよ.

■ 受講のためのシステム環境 … 習熟度別 ■
習熟度分類 環境
まったくの初心者 通常の方法でログインした環境そのまま.

目的, 装置 ツール,説明
文字端末 GNOME端末, kterm
エディタ Xemacs (別ウィンドウ)
web browser Mozilla (別ウィンドウ)
キーボード 数字キー,カーソルキーなどてんこ盛り. マウスも使っちゃうぞ.


という「三輪車に補助輪をつけたぐらい甘ちゃんの」環境である.

便利だが,いざというときの能力はあまり身につかないため, 早めにこの「ぬるい」環境から抜け出られるように努力すること.
中級者 通常の方法でログインした後, 画面一杯に GNOME端末, kterm を広げた環境.

目的, 装置 ツール, 説明
文字端末 GNOME端末, kterm
エディタ emacs -nw of vi (GNOME端末, kterm 中で)
web browser lynx or w3m (GNOME端末, kterm 中で)
キーボード 数字キー,カーソルキーなど不要だ. ログイン,ログアウト時以外ではマウスも不要だ.

という環境である.

unix cui 環境で一通り作業ができるようになる,という目的のためにはこの環境が適当だろう.
ただし, いざというときに他のアプリケーションに頼ったり,複数の GNOME端末, kterm を立ち上げられるという「逃げ」がある点や, 「日本語が使える」点がまだ甘い(^-^).
上級者(の下) unix を文字端末モードに切り替えてログインした環境.
X windows を立ち上げてない状態.


目的, 装置 ツール, 説明
文字端末 ログインコンソール
エディタ emacs or vi
web browser lynx or w3m
キーボード 数字キー,カーソルキーなど不要だ. マウス? なにそれ? 食べられるの?

という環境である.

「unix cui 環境で一通りの作業ができます」というには, 「この環境で日本語以外は困りません」といえないといけない.

この環境で(日本語以外は)全く不自由なくなれば,ユーザとしては上級者(の下)とみてもよかろう.
初心者なども,unix cui 環境とは本来どのようなものかを体感するために, 一度はこの環境にチャレンジしてみると良い.

ちなみに,上級者の上クラスになると「普通のモニタ無しで」作業できる. 当然, emacs や vi などのような「甘やかされた」エディタを使わずに, ed などのエディタで十分作業ができる.

実習

上記の「上級者環境」を一度試してみよ.
ただし,具体的な方法についてはいろいろと問題があるので,授業時に説明する.

プロセスとジョブ, マルチタスクについて

unix はマルチタスクシステムであり, ユーザはその恩恵を最大限に利用するべきである. しかし,gui では直感的に理解できるマルチタスクも cui ではその状態が見えにくい. そのため,cui 初心者状態ユーザはせっかくのマルチタスクを生かせずに dos のようなシングルタスク環境とあまり変わらない状態で unix cui 環境を利用していることがまま見受けられる. こうした状況は大いなる時間の無駄といえる.
そこで今回の授業では,ユーザがプロセスやジョブを制御するとはどういうことかを学び, その知識を生かして cui 環境でも大いにマルチタスクの恩恵を受けられるようになることを目指す.

さて,ユーザから見た場合,プロセス制御とジョブ制御はほとんどシームレスに繋がっており, 区別する必要は余りない. しかしその為にかえって理解が深まらないことが多い.
そこでプロセス制御とジョブ制御を明確に区別して学習し,理解してから それらを使いこなすことを目的とする.

マルチタスクとは…
同時に複数の処理をこなすこと,もしくはそれらの処理. コンピュータの場合,この処理とはだいたいプログラムのことだと思ってよいだろう.
# マルチタスクなシステムとしては,unix, windows, mac os などが挙げられるだろう. 逆に,dos などはシングルタスクシステムであり,(実質的には) 一度に一つのプログラムしか動作させられない.
unix システムがマルチタスクシステムであることから, 以下に解説するプロセス & ジョブ制御が必要となってくる.

プロセス

プロセスとは

プロセス
unix のようなマルチタスクシステムでは,同時に多くのプログラムが動作している. しかし,一つのプログラムを良くみると様々な機能から構成されている. そこで,こうした機能毎に動作を分離することで,様々な処理を能率良く,かつ より分かりやすく安全に行なうことができる.
この時の,コンピュータ上で動作する最小単位をプロセスと言う(言った). (つまり,一つのプログラムは複数もしくは一つのプロセスからなる).
# 実際は,動作時間やリソース(Resource, 資源)をさらに効率的に用いるために,プロセスをさらに細分化した「スレッド」という概念がある.
# ただし,スレッドはそれ自体ではあまり独立した存在ではないため, ユーザが制御できる最小単位はプロセスということになる.

よって,コンピュータの動作は, 「多くの(ほぼ独立な)プロセスが同時に動作している」と理解すればよい.

プロセス制御
unix 上ではほぼ常に多数のプロセスが(擬似的に同時に)動作している. この時,個々のプロセスを(一時)停止したり, 優先順位を上下させたりすることができないと, 何かトラブルが起きたときなどにシステムを停止するしか手段がないことになる.
個々のプロセスの動作とシステムそのものの動作を独立にするために提供される手段, それがプロセス制御である.
また,プロセス制御を適切に行なうことにより,システム全体のパフォーマンスを上げることも可能である.

プロセスの親子関係
unix では,全てのプロセスはなんらかのプロセスによって生成される. これを「親子関係」と見なして,もとのプロセスを新しいプロセスの 「親プロセス」と呼ぶ.
「子プロセス」の「死体処理(ゾンビ状態のプロセスを消滅させること)」をするのは親プロセスの役目であるため, 子プロセスが親プロセスよりも先に死ななければいけない.
よって,何らかの理由により親プロセスが先に死んでしまった場合, ゾンビになった子プロセスの処理が難しくなることがある.

プロセスの状態を知る

ps コマンド

プロセスの状態を知るには,ps コマンドを用いる.
ただし,そのままだと「自分が実行した」プロセスしか表示されない. 他人が実行しているプロセスなども見たいときは, 適切なオプションを用いる必要がある.
お勧めはとりあえず ps -axu である. より詳しい情報を知りたいときは,man ps でオンラインマニュアルをひくこと.

ちなみに… 便宜のために記しておくと,ps -O キーワード でそのキーワードに相当する情報を二番目のヘッダとして得られる.

ps コマンドの使い方による違いの例
コマンド 結果例
ps
  PID TTY          TIME CMD
29452 pts/0    00:00:00 sh
29475 pts/0    00:00:00 tcsh
31982 pts/0    00:00:00 ps
        
ps -axu
USER       PID %CPU %MEM   VSZ  RSS TTY      STAT    START   TIME COMMAND
root         1  0.0  0.0  1116   64 ?        S       May22   0:05 init [5]
root         2  0.0  0.0     0    0 ?        SW      May22   0:00 [kflushd]
root         3  0.0  0.0     0    0 ?        SW      May22   0:00 [kupdate]
root         4  0.0  0.0     0    0 ?        SW      May22   0:05 [kswapd]
        
…略…
ot-026fd 29452  0.0  0.8  1888 1132 pts/0    S       15:07   0:00 -sh
root     29455  0.0  0.0     0    0 ?        SW      15:07   0:00 [rpciod]
root     29456  0.0  0.0     0    0 ?        SW      15:07   0:00 [lockd]
ot-026fd 29475  0.0  1.0  2332 1328 pts/0    S       15:07   0:00 -csh
root     31202  0.0  7.3 35344 9412 ?        S       16:36   0:02 /etc/X11/X -au
root     31203  0.0  0.7  3188  952 ?        S       16:36   0:00 /usr/bin/gdm -
root     31211  0.0  3.6  6956 4684 ?        S       16:36   0:00 ruby /etc/ecip
root     31212  0.0  0.9  2320 1216 ?        S       16:36   0:00 /usr/bin/xpeng
gdm      31214  0.0  2.9  6688 3756 ?        S       16:36   0:00 /usr/bin/gdmlo
ot-026fd 31984  0.0  0.6  2460  796 pts/0    R       17:45   0:00 ps -axu
        

ps コマンドで見られる情報のうち,重要なものをいくつか解説しておこう.

■ ps コマンドで見られる情報の主なもの(指定できるキーワード) ■
キーワード 意味
pid プロセス ID. 各々のプロセスに固有な番号. 人間で言えば,個人名である.
プロセスの制御はこの PID を基本として行なわれる.
user ユーザ名. そのプロセスの利用者.
注) 通常ユーザは,自分が利用しているプロセスしか制御できない.
%cpu cpu 利用率. 通常は数〜数十パーセント程度であり, この数字が異様に高い(100% に近い)状態が長時間続き, かつ,負荷の高いプロセスを走らせているつもりがなければ, そのプロセスが暴走している可能性がある.
%mem メモリ使用率. これも暴走しているプロセスでは大きくなる傾向がある.
tty 制御端末名. そのプロセスがどの「端末」に属しているかを示す.
stat プロセスの状態. 一文字ずつある状態を意味する. 主要なものを示しておこう.

記号 意味
S プロセスは sleep 状態(キーボード入力完了待ち)である.
R プロセスは実行可能状態.
D プロセスはディスク入出力完了待ちである.
T プロセスは停止(stop)中である.
Z プロセスはゾンビ(zombie, "死んでいる")である.

この stat を見ればプロセスの状態がわかる. T や Z という状態は(思い当たる節がなければ)何か異常が起こっていることを示唆する. また,長時間 D のままという場合も,何かおかしい可能性が高い.
command コマンド名と引数
pri (スケジューリング)優先度. 0 〜 127 の数字で,小さい方が優先度が高い.
ni nice 値. この数字とプロセスの性格などから優先度が決定される. -20 〜 20 程度の数字で,小さい方が優先度を高くできる. デフォルトは 0.


top コマンド

ps コマンドの他にも, top コマンドで,プロセスの状態を「動的」かつ「連続的」にみることができる.

このコマンドはどちらかというと,プロセスがどれくらい「重い=負荷が高い」 のかをみるために使われる.
具体的には,オンラインマニュアルで調べること.

実習

ps コマンド, top コマンドの各々を試してみよ.
オプションもいろいろ変えてみて, 自分の欲しい情報が得られるようにしてみよ.

プロセスを制御する

プロセスを作る,動作させる

プロセスとは上に述べたようにプログラムを構成する単位であるため, ユーザから見たとき,プログラムを実行することは即ちプロセスを生成することである.
逆に,プログラムの実行が完全に終わったときには, そのプログラムによって作られたプロセスは全て消滅した,ということになる.

プロセスの優先度を変更する

プロセスには「優先順位」というものがあり, 優先順位が高い方がより先に実行されるようになっている. この仕組みにより,様々なプロセスが同時に動作しても 人間にとって快適に扱えるようになっている.
このプロセスの優先順位を意識的に変更する方法があり, これを用いると unix をより快適に使えるようになるだろう.

ちなみに,プロセスの優先度と nice 値を見るには, ps l (← 小文字のL(エル))とするのが簡単だ.

■ プロセスの優先度を変更するコマンド ■
コマンド名 解説
nice プログラム起動時に nice 値を決定する.
注) csh 系のシェルには nice コマンドが組み込まれていることがあり, システムに既に存在する nice コマンド(/bin/nice)と混同しやすい.
どちらも働きは同じだが,実際の使い方は異なるため, 使うときは必ずオンラインマニュアルで調べる必要がある.

/bin/nice -数字 コマンド

システムの nice を用いて何かプログラムを起動する. 「数字」部分には nice 値を指定する. 通常ユーザは 0〜20 しか指定できない(つまり,優先度は下がる).
renice 既に動いているプロセスの nice 値を「増やす」=「優先度を下げる」.
動作中のプロセスのせいでコンピュータの反応が鈍くなるなどの場合に, プロセスの優先度を下げて作業を快適にする,等の目的で用いる.
一度優先度を下げたプログラムの優先度を元に戻すことは出来ない. つまり,いかなる場合でも通常ユーザは nice 値を増やすことしか出来ない.

スーパーユーザだけは,nice 値を減らす,つまり優先度を上げることができる.

プロセスを終了させる(プロセスを殺す)

unix のプロセスには「プロセス間通信」といってプロセス同士が通信する仕組みが備わっている. このプロセス間通信のうち,メッセージを伝えるだけの機能を持つものとして「シグナル」がある.
このシグナルをプロセス宛に送りつけることによって,プロセスを停止させたり,再起動させたり,殺したりできる. (ただし,自分の利用しているプロセスにしかシグナルは送れない)

シグナルをプロセスに送りつけるには,
kill -シグナル pid
とする. シグナルは後述する「シグナル名」か「シグナル番号」で指定する.
シグナルを省略すると TERM (=15) を指定したことになる.

■ kill コマンドで用いるシグナル ■
シグナル番号 シグナル名 シグナルの意味
15 TERM TERMinate. 終了. kill コマンドのデフォルト.
9 KILL KILL. 「強制」終了. このシグナルを受け取ったプロセスは必ず死ぬ.
2 INT INTerrupt. 端末から割り込み(CTRL-c)を受けた,という意味. このシグナルを受けるとプロセスは死ぬ.
3 QUIT QUIT. 端末から中断終了(CTRL-\)を受けた,という意味. このシグナルを受けるとプロセスは(core を吐いて)死ぬ.
18 TSTP TerminalSToP. 端末から停止(CTRL-z)を受けた,という意味. このシグナルを受けるとプロセスは(一時)停止する.
17 STOP STOP. 「強制」停止. このシグナルを受けるとプロセスは必ず停止する.
19 CONT CONTinue. 停止状態のプロセスの実行を再開する.
1 HUP HangUP. 端末回線が切れた,ということを意味する. 普通のプロセスはこのシグナルを受けると実行を中止するが, 再起動したり特別なモードに移行するプロセスも多いので注意が必要だ.

この表から分かるように,どうしてもそのプロセスを殺したい場合は,
kill -9 pid
とするか,
kill -KILL pid
とすればよい,ということになる.

ちなみに… state が D のプロセスや,zombie プロセスには kill -KILL が有効でない場合がある. こういう場合は,特に支障がなければ放置(^-^),支障がありそうだったら 管理者に相談するのが良い.
ちなみに… シグナル "HUP" や pid "1" "0" "-1" は特別な意味で使われることが多いので, よくわからない場合は使わないように注意すること.
酷い目にあってみたい,という酔狂な人は自宅の unix などでスーパーユーザになって, kill 1, kill -KILL -1 などといろいろやってみよう(^-^).

nohup コマンド

プログラムが動作中であっても,GNOME端末, kterm を終了したりログアウトしたりすると通常はそのプログラムは終了してしまう.
これは,そのプログラムを起動した環境が,終了する直前にそのプログラムに対して上の HUP シグナルを送っているためである.

通常はこれは便利だが,大量の計算をするときなどに 「ログアウトした後もプログラムは動きつづけたままでいて欲しい」 ということがある.
こうしたときには, nohup コマンドを用いて nohup コマンド名 としてプログラムを起動すると,ログアウトしてもこのプログラムが動作し続けるようにできる.
また,コマンドを指定しないでただ nohup としてしまうと,それ以降のコマンド全てが nohup 扱いになる. ただし,こうなると初心者はいろいろと困る恐れがあるので,気をつけること.
# より詳しい使い方については,オンラインマニュアルを見ること.

あと, nohup コマンドを用いる際は,nohup 指定をしたプログラムの動作によって 他のユーザに迷惑がかからないように留意すること.
例えば,nohup 指定をしたプログラムが CPU に大きな負担をかけるために, そのマシンを使う他のユーザが「このマシンは遅くて使えねー」ということ がないように,ということである.
ちなみに,こういうときは事前に nice コマンドなどで該当プログラムの優先順位を下げておけばよい.

実習

次の手順でプロセス制御を試してみよ.

  1. GNOME端末, kterm 中で emacs -nw と入力して emacs を起動する.
  2. emacs が起動している状態で CTRL-z として,emacs を停止状態にする.
    # CTRL-z や停止状態の説明は後述する.
  3. ps コマンドを試してみて,emacs の存在とその状態を把握する.
  4. top コマンドを試してみて,emacs の存在とその状態を把握する.
  5. ps コマンドで emacs の PID を把握し, kill コマンドを用いて emacs を強制終了させる.
  6. ps コマンドで emacs が存在しない(強制終了したため)ことを確認する.

ジョブ

ジョブとは

ジョブとは,(シェルから見た)コンピュータ上で実行される実態の単位の概念で, 「一連の仕事をしている(複数の)プロセス」 のことである.
まあ簡単に言えば,シェルで命令した「(一行分の)命令の固まり」であり, 人間にとって一つの処理と見なせるもの,と思えばよい.
# シェルの history コマンドで「一回分」のコマンドと思ってもよい.

既にプロセスという概念があるのに, なぜわざわざ 新しくジョブという概念を持ち込むのか?

プロセスというのは,あくまで「コンピュータ側から見た」概念である. それは正確で確実な概念であるが,利用者との関係はほとんど考慮されていない.
そこで,「ユーザにとっての実行単位」としてジョブという概念を定義し, そのジョブ単位をユーザから「見えなくしたり見えるようにしたり」することで マルチタスクを使いやすくする,というのがジョブという概念の根底に流れる思想である.

フォアグラウンド,バックグラウンド

シェルは人間と「対話的」に動作するのが基本であるため, シェルの上で素直に複数のプログラムを同時に動作させるとキーボードの入力等が混乱するのはミエミエである(^-^).
しかし,マルチタスクシステムである unix であるのに, シェル中では同時に複数のプログラムを使えないというのも意味がない. そこで,「人間と対話しながら作業するジョブを一つだけ」と 「そうでないジョブ(複数)」 をわけることでマルチタスクを可能としている.

フォアグラウンド
シェルを通じて人間からのキーボード入力を受けるジョブをいう. つまり,通常使っている状態のジョブはフォアグラウンドにいるのである.
キーボードは一つしかないので,フォアグラウンドジョブは常に一つしか存在できないことに注意.

バックグラウンド
人間のキーボード入力を受けられない状態で動作している時,そのジョブは 「バックグラウンドで動作している」と言う. この状態で動作するジョブは複数あってもよい.

(停止状態)
起動はしているが,動作を停止している状態.
フォアグラウンドにもバックグラウンドにいられなくなったジョブが 強制的にこの状態に移されることもある. また,ジョブをフォアグラウンドからバックグラウンドへ持っていくときの途中の状態としても用いられる.
詳しくはプロセスの state の該当する部分を参照せよ.

ジョブの状態を知る

そのシェルから見たときにどれだけのジョブがどういう状態にあるかは,
jobs
コマンドで知ることができる. 例えば,阪大教育用計算機システムで jobs コマンドを実行してみると, 下のような表示が得られる.

jobs コマンドの実行例

[1]  - 終了                          ls --color=auto -Fga -l |
       中断                          less
[2]  + 中断                          emacs
    

この表示は左から,
ジョブ番号 状態 コマンドと引数
というリストになっている. ジョブ番号に「+」がついているのは,下の kill, fg, bg コマンドで %ジョブ番号 を省略した場合にデフォルトで使われる番号がこれであることを意味している. (だいたいは一番大きい番号だ)

ちなみに,この例では二つのジョブが「中断」状態,つまり「停止状態」であることがわかる.

実習

GNOME端末, kterm 中で emacs -nw & と何度か入力するなどして, jobs コマンドの様子を試してみよ.

ジョブを制御する

ジョブ制御とは,ジョブを三状態のある状態から他の状態へと移動させることや, プロセス制御と同じくジョブを「殺したり」することを言う.

■ ジョブ制御の様子 ■
job control figure
ジョブには大まかにいって上図のような三つの状態があり得る.
図中にあるようなコマンドを用いてジョブの状態を変遷させることが ジョブ制御の中心となる.
一見ややこしいが,この図式さえ理解すればあとはおいおい身につくだろう. 詳細は以下に述べる.

ジョブを作る

ユーザから見たとき,シェルを通じてプログラムを実行したとき, シェルに投入された一塊のコマンド(群)がジョブとして生成される.
この時,実行時のオプションによって,どの状態として起動されるかが変わってくる.

コマンド名の最後に「& をつけないで」起動する … フォアグラウンドジョブとして起動する.

コマンド名の最後に「& をつけて」起動する … バックグラウンドジョブとして起動する.
例えば,x window system が動作しているときに GNOME端末, kterm 中で xemacs & とすると,xemacs が「別窓で」起動するのが見られるが,これがそうである.

ジョブの状態変遷 (1)
フォアグラウンドとバックグラウンドの行き来

fg %ジョブ番号
そのジョブ番号をもつジョブをフォアグラウンドへ移す(入出力を人間相手にする).

ちなみに…

上の図からも分かるように,ジョブを フォアグラウンド → バックグラウンド と直接移行する方法はない. そうしたい場合は, フォアグラウンド → 停止状態 → バックグラウンド という経路でバックグラウンド状態にする.
# 要するに, CTRL-zbg %ジョブ番号 というコンボである. この二つのコマンドの組合せはよく使うので,覚えてしまった方がよい.

ジョブの状態変遷 (2)
フォアグラウンドと停止状態の行き来

CTRL-z
フォアグラウンドジョブを停止状態にする.
ただし,シェルそのものだけはこれで停止しないようになっている(例外措置).
# シェルを停止したい場合は, suspend コマンドを用いる.

fg %ジョブ番号
そのジョブ番号をもつジョブをフォアグラウンドへ移す(稼働状態にする).

ジョブの状態変遷 (3)
バックグラウンドと停止状態の行き来

bg %ジョブ番号
そのジョブ番号をもつジョブをバックグラウンドに移す(黙って動作させる).

stop %ジョブ番号
そのジョブ番号をもつジョブを停止状態にする(動作を停める. 終了ではない).

ジョブを殺す

フォアグラウンドジョブ,即ち,人間と対話しながら動作しているジョブは CTRL-c などで殺すことができる. これは コマンド操作の基本 でも示した通りである.
ただし,シェルそのものだけはこれで死なないようになっている(例外措置).

そうでないジョブ(他の状態にあるジョブ)は,上の jobs コマンドでそのジョブ番号を調べて,
kill %ジョブ番号
とすればそのジョブを殺すことができる.

ちなみに… nice 同様, kill もシェルの組み込みコマンドとシステムのコマンドの両方がある. ただし,直感的な動作の違いは余りないので気にせずに済むだろう.

実習

次の手順でジョブ制御を試してみよ.

  1. touch コマンドを用いてファイルを新しく作る.
  2. 作ったファイルを GNOME端末, kterm 中で vi か emacs で編集し(ジョブの投入),適当に数行書き込む.
  3. vi or emacs を終了せずに,停止させることでシェルへ戻る(ジョブの停止).
  4. less コマンドを用いて編集したファイルを見る(ジョブの投入 & 停止).
  5. date コマンドを用いて日時を調べて…(ジョブの投入 & 停止).
  6. fg コマンドを用いて vi or emacs へ戻り(停止ジョブをフォアグラウンドへ)
  7. 先ほど調べた日時を書き込んでから, vi or emacs を終了(ジョブの停止).
  8. 再び, less コマンドを用いて編集したファイルを見て, 先ほどの日時書き込みが保存されていることを確認(ジョブの投入 & 停止).

レポート課題(20点満点)

以下に示された課題について

AppliedMath-Report-03

という題名をつけて e-mail にて教官宛にレポートとして提出せよ(教官のメールアドレスは授業中に口頭で伝える).
なお,レポートを e-mail の代わりに TeX で作成した書面にて提出してもよい.

課題内容

  1. ジョブを投入して停止状態にする方法を複数述べよ.

    また,これらの作業を実際にやってみよ. ただし,この操作の様子を script コマンドで記録しておいて,その記録を提出する形で報告すること.

  2. kill でもプロセスが殺せない場合が何通りか考えられる. そのうち,3種類を挙げてきちんと解説せよ.

  3. ジョブを あわせて 5つほど投入し,全てが共存する状態にし, 三状態を自在に遷移させよ. ただし,この操作の様子を script コマンドで記録しておいて,その記録を提出する形で報告すること.




最終更新日 … $Date: 2006/04/25 19:37:18 $
Valid CSS! Valid XHTML 1.1!