はうすてんぼぶ

コードかいてて疑問に思ったことや、興味あることをつらつらと暇なときに書く場所、ここはそんな場所

プロセスについて

「プロセス」って何気なく使っているけど、その実本当によくわかっていなくてやばいので、ここに調べて動かしてみた結果を載せとく。

ジョブとプロセス

ジョブ

コマンドを指定して実行すると、それが「ジョブ」という実行単位になる。

現在のジョブの単位はjobsコマンドで知ることができる。

プロセス

ジョブをもっと細かい単位に分けたものを「プロセス」と呼ぶ。

例えば、manコマンドを例にすると、UNIX内部ではどうなってるか見てみる。

% man cat &
[1] 15582
% 
[1]  + suspended (tty output)  man cat

% ps
  PID TTY          TIME CMD
15573 pts/0    00:00:00 zsh
*15582 pts/0    00:00:00 man
*15586 pts/0    00:00:00 man
*15587 pts/0    00:00:00 man
*15588 pts/0    00:00:00 preconv
*15589 pts/0    00:00:00 man
*15590 pts/0    00:00:00 man
*15591 pts/0    00:00:00 tbl
*15592 pts/0    00:00:00 nroff
*15593 pts/0    00:00:00 pager
15595 pts/0    00:00:00 ps

*を付けた行がmanコマンドを読んだときに実際呼ばれるプログラムである。

なんか無駄にmanコマンドが何度も呼ばれているのが気になるが、それぞれの行が1つの「プロセス」なのは間違いない、はず。

ジョブ番号とプロセス番号

ジョブ番号はターミナルごとに1から連番で振られるもの。
上の例だと、

% man cat &
[1] 15582

の[1]がそれに当たる。これはターミナル間で独立して持っているので複数のターミナルで重複しても問題なし。

プロセス番号は、UNIXの本体が管理しているため、必ず一意になる。
上の例だと、

% ps
  PID TTY          TIME CMD
15573 pts/0    00:00:00 zsh
15582 pts/0    00:00:00 man
15586 pts/0    00:00:00 man

PID(Process ID)がそれに当たる。

バックグラウンドで呼ぶ

さっきからちょいちょいコマンドの最後に「&」を付けて読んでいるけれども、この&を付けるとそのジョブがバックグランドで呼び出されるようになる。

重たい処理をする場合はバックグランドで実行すると、処理を止めずに他の作業に専念できる。

% find / -name file1 -print &

こんな風にすると時間がかかる検索もすぐプロンプトが表示されるので他の作業ができる。

問題は、出力先はデフォルトのままなのでターミナルにそのままガリガリでてきてしまう点。

なので、こういう場合はリダイレクトしてファイル当たりに出力するととっても快適。処理が終わったことに気付けないのがちょっと難点だけれども…。

jobs

現在起動しているジョブ一覧はjobsコマンドで見ることができる。

% jobs
% jobs -l

-lを付けるとプロセス番号も表示される。

実行結果は以下のようになる。

% man cat &
% man ls &
% ./test_sh > test.txt &
% jobs -l
[1]  - 16004 suspended (tty output)  man cat
[2]  + 16017 suspended (tty output)  man ls
[3]    16031 running    ./test_sh > text.txt

suspendedは停止中、runningは実行中のジョブの状態を示す。

ジョブ番号とプロセス番号の間にある+や-の記号は以下のプロセスのことがわかる。

+ 直前に実行したプロセス
- 直前のさらにひとつ前に実行したプロセス
無印 それより前に実行したプロセス

ps

psコマンドを使うことでプロセス情報を見ることができる。

psのオプションは「-」を付けた場合と付けない場合で効果が異なったりするので、マニュアルをしっかり読む必要がありそう。
逆に考えると、それっくらいオプションをたくさん付けられる、ということ。

参考書に載っている主なオプションだけ表形式で載せておく。

a 自分以外のユーザのプロセスについても表示
f 実行命令の親子関係をツリー状に表示
l 詳細情報を表示
u ユーザ形式で表示、ユーザ名(USER)などが表示される
x 制御端末のないプロセス情報も表示
w 出力の幅を広げる。標準では長い情報も1行80文字で着られる

試しにfを付けて実行してみた結果を載せる。

$ ps f
  PID TTY      STAT   TIME COMMAND
16082 pts/0    Ss     0:00 zsh
16088 pts/0    TN     0:00  \_ man cat
16092 pts/0    ZN     0:00   |   \_ [man] <defunct>
16093 pts/0    TN     0:00   |   \_ man cat
16095 pts/0    TN     0:00   |   \_ preconv -e UTF-8
16096 pts/0    TN     0:00   |   \_ man cat
16097 pts/0    TN     0:00   |   \_ /bin/sh /usr/bin/nroff -mandoc -Tutf8
16098 pts/0    TN     0:00  |   \_ pager -s
16137 pts/0    S      0:00   \_ bash
16191 pts/0    T      0:00       \_ man cat
16196 pts/0    T      0:00        |   \_ man cat
16197 pts/0    T      0:00        |   \_ preconv -e UTF-8
16200 pts/0    T      0:00        |   \_ tbl
16201 pts/0    T      0:00        |   \_ /bin/sh /usr/bin/nroff -mandoc -Tutf8
16202 pts/0    T      0:00        |   \_ pager -s
16203 pts/0    R+     0:00        \_ ps f

ちょっと見づらいが、zshのときとbashのときでmanコマンドのプロセスが異なるんだなぁとちょっと不思議に思った。

フィールドに関しては、ひとまずSTAT(プロセス状態)を見て分かるようになりたいのでまとめておく。

R 実行中
S 休眠中
D 割り込み不可能な休暇中
T 停止
Z ゾンビプロセス

zshのときのSTATにあるTNやSsなどは最初の一字はわかるが2文字目の意味がわからなかった…。

bg

バックグラウンドジョブを実行する場合はbgコマンドを用いる。

bgが呼べるジョブは、「現在バックグラウンドにあって」かつ「停止中」である必要がある。停止中かどうかはjobsコマンドを見ればすぐ分かる。

使い方は以下の通り。

bg
bg +
bg %(JobNumber or JobName)
bg -

一番上と二番目は同じで、カレントジョブをバックグラウンドで再実行する際に用いる。

三番目はジョブ番号かジョブ名を指定して再実行する。ジョブ名は複数マッチした場合はエラーが出る点に注意。

四番目は-記号のついたジョブ、つまり直前のさらに一つ前に実行したものを再実行する。

fg

bgコマンドはバックグラウンドのジョブをバックグラウンドで再実行させるのであれば、fgコマンドはバックグラウンドのジョブをフォアグランドにして再実行させるコマンド。

使い方はbgと同じなので割愛。

kill

物騒なコマンド名だが、その役割は文字通り「殺す」ことが主。

また、killコマンドは、ジョブやプロセスを殺す他に、指定したシグナルをジョブやプロセスに送ることもできる。

まず使い方に関して載せる。

% kill [PID] //プロセスIDを指定してプログラムを終了
% kill %[JobNumber] //ジョブ番号を指定してプログラムを終了
% kill -l //シグナル一覧を表示
% kill  -s [SIGNAL] [PID]//プロセスIDに指定したシグナルを送る(ジョブ番号でも同じことができる)

バックグランドで走っているジョブを殺したい場合は、そのジョブ番号かプロセスIDを用いてkillコマンドを呼べばおっけー。

シグナル

一覧を見るためには、上にも載せたが

% kill -l

で見ることができる。

実際に実行してみた結果を載せる、

% kill -l
HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS

け、結構ある…。

UNIXコマンド [kill]を参考に終了させる系のものだけ載せる。

番号 シグナル 説明
1 HUP 終了後再起動
2 INT ユーザからの強制終了命令(Ctrl + cと同じ)
9 KILL プロセスの強制終了
15 TERM 正常な終了動作を行わせて安全に終了

シグナルは特に指定しなければTERMが送られる。
でも、上の表を見るとわかるがTERMシグナルは結構生ぬるいので、本当に殺したいときはKILLやINTで良い気はする。

おわりに

プロセス管理の基礎はだいたいこれで全部だと思う。

シグナルに関しては数は多いが使うのは限られているはずなので、少しずつ慣れていきたい。