Linux標準教科書 第11章

プロセス管理

11.1 プロセスとは

Linux では実行中のプログラム(アプリケーション)を管理する単位をプロセスと呼びます。シェル自身もプロセスです。「ユーザがシェルからコマンドを実行すると、シェルは子プロセスとして自分の分身を作ります(fork)。次に、シェルは子プロセスにコマンドの実行(exec) を任せ、子プロセスの終了を待ちます。子プロセスはコマンドの実行を終えると親プロセスに終了を伝え、消滅します。親プロセスは子プロセスの終了を受け取り、シェルプロンプトを表示し、ユーザの次のコマンドに備えます。

11.2 スケジューリング

それぞれのプロセスの実行順序は Linux のスケジューラによって管理されています。各プロセスはキューで待機しますが、プロセスによっては優先度の高いもの、それほど高くないものもあります。そのパラメータの一つに Nice 値があります。Nice 値は、-20 から 19 までの値を取り、-20 が最も実行優先度が高く、19 が最も低くなっています。nice コマンドにより実行優先度をプロセスに指定したり、実行中のプロセスについては、renice コマンドにより優先度を変更することができます。

11.3 フォアグランドジョブとバックグランドジョブ

プロセスとよく似た管理単位としてジョブがあります。Linux が実行中のプログラムを管理する単位であるプロセスに対して、ジョブはシェルが管理するプログラムの単位です。シェルからコマンドを実行する場合、ジョブをフォアグランドとバックグランドに切り替える機能があります。パイプを使って複数のプロセスを実行する事ができます(ジョブは一つの単位となります)。

コマンドをバックグランドで起動するには、コマンドの後ろに & (アンパサンド)をつけて実行します。

$ my_heavy_script &

実行中のコマンドをバックグランドに切り替えるには、 ^Z ( CTRL+Z ) でサスペンドしてから、bg コマンドでバックグランド実行を継続させます。fg コマンドでフォアグランドに戻すこともできます。ジョブの状態は、jobs コマンドで確認する事ができます。

実習: 複数のジョブを実行して、切り替えを試してみましょう。

$ sleep 3600&           (1時間(3600秒)スリープするプロセス)
$ sleep 3601&
$ sleep 3602&
$ jobs
[1] 実行中 sleep 3600
[2]- 実行中 sleep 3601 &
[3]+ 実行中 sleep 3602 &
$ %1                  ([1]のジョブをフォアグランドジョブにします)
sleep 3600
^Z                                      (CTRL+Z でフォアグランドをサスペンドします )
[1]+ 停止  sleep 3600
$ jobs
[1]+ 停止  sleep 3600
[2] 実行中 sleep 3601 &
[3]- 実行中 sleep 3602 &
$ %-                                   ( – のついたジョブをフォアグランドジョブにします)
sleep 3602
^C                                       (フォアグランドにあるジョブを停止します)
$ %%                                 ( + のついたジョブをフォアグランドジョブにします)
sleep 3600
^C                                    (フォアグランドにあるジョブを停止します)
$ fg                                    (この場合の fg は fg %+ , %+, %% と同じ動作になります)
sleep 3601
^C                                    (フォアグランドにあるジョブを停止します)

11.4 プロセス ID

Linux のプロセスには、一意の ID であるプロセス ID(PID) がふよされます。自身(シェル)の PID は && で取得できます。

$ echo $$
5093

$ ps [オプション]      現在実行されているプロセスのスナップショットを表示します

$ sleep 3600 &
[1] 5775
$ ps l
F UID    PID    PPID  PRI  NI        VSZ   RSS   WCHAN   STAT     TTY      TIME     COMMAND
4 1000  5093  5092   20   0   115496  2124   wait        S          pts/0     0:00     -bash
0 1000  5775  5093   20   0   107892   612    hrtime     S          pts/0    0:00      sleep 3600
0 1000  5776  5093   20   0   121276   028    –             R+        pts/0    0:00      ps l

ps に l オプションを指定すると、PID だけでなく PPID( 親プロセスの ID ) も表示されます。 ps の親プロセスが -bash である事がわかります。

$ jobs
[1]- 実行中 sleep 3600 &
$ %-
sleep 3600
^Z
[1]+ 停止 sleep 3600
$ jobs
[1]+ 停止 sleep 3600

11.5 シグナル

Linux には、プロセスにシグナルといイベントを送信してプロセスを制御する機能があります。シグナル番号およびシグナル名が割り当てられており、代表的なものに以下のシグナルがあります。

ユーザがプロセスにシグナルを送信する方法は3つあります。
・シェルに割り当てられたキーの入力(例 : ^C, ^Z, ^\ など)
・kill コマンド(例 : kill-HUP PID, kill-SIGINT PID, kill-9 PID など)
・プログラムで kill() 関数を呼ぶ

kill -l コマンドでシグナルの種類を表示する事ができます。

$ kill -l
1) SIGHUP           2) SIGINT      3) SIGQUIT        4) SIGILL       5) SIGTRAP
6) SIGABRT         7) SIGBUS      8) SIGFPE         9) SIGKILL    10) SIGUSR1
11) SIGSEGV      12) SIGUSR2  13) SIGPIPE     14) SIGALRM  15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD  18) SIGCONT    19) SIGSTOP  20) SIGTSTP
21) SIGTTIN       22) SIGTTOU  23) SIGURG     24) SIGXCPU  25) SIGXFSZ
26) SIGVTALRM  27) SIGPROF  28) SIGWINCH  29) SIGIO      30) SIGPWR

実習: 無限ループするシェルスクリプトを作成します。

$ vi loop
#!/usr/bin/sh
while /bin/true
do
sleep 3600
done
:w
^Z
$ chmod 755 loop
$ ./loop
(シェルスクリプトが帰ってきません)
^C ← CTRL+C を押す事で、INT(Interupt Signal) が送信され、loop を終了する事ができます
$

先ほど作成したシェルスクリプト”loop” に trap 処理を挿入します。

$ fg
#!/usr/bin/sh
trap ‘echo “…CTRL+C is pressed.”‘ 2     #trap にてSIGINT(2)を受信した時に中止
while /bin/true
do
sleep 3600
done
:w
^Z
$ ./loop          ← 無限ループに入ったので、^C を推しますがプロンプトが戻りません
^C…CTRL+C is pressed.
^C…CTRL+C is pressed.
^Z            ← ^Z でサスペンドして kill コマンドでデフォルトの TERM シグナルを送信
[3]+ 停止 ./loop
$ kill %%
[3]+ 停止 ./loop      ← 終了しました

実習: ps alx を実行して、PID が一番小さなプロセスが何か確認してみましょう。

$ ps alx
F  UID  PID  PPID  PRI    NI       VSZ    RSS   WCHAN   STAT  TTY  TIME   COMMAND
4     0      1      0    20      0   54192   3912   ep_pol     Ss      ?     0:00    /usr/lib/systemd
1     0      2      0    20      0          0         0   kthrea     S        ?     0:00   [kthreadd]
1     0      3      2    20      0          0         0   smpboo   S        ?     0:02   [ksoftirqd/0]
1     0      5      2      0   -20          0         0   worker    S<      ?     0:00   [kworker/0:0H]

実習: sleep コマンドを2つ、バックグランドで実行し、ps l で親子関係を確認しましょう

$ sleep 3600 &
[3] 6114
$ sleep 3601 &
[4] 6115
$ ps l
F    UID   PID  PPID PRI NI       VSZ   RSS  WCHAN   STAT  TTY     TIME  COMMAND
0  1000 3500 3499  20   0  115656  2164  wait        Ss      pts/0   0:00  -bash
4  1000 5093 5092  20   0  115656  2212  wait        S       pts/0   0:00  -bash
0  1000 6114 5093  20   0  107892  612    hrtime    S       pts/0    0:00  sleep 3600
0  1000 6115 5093  20   0  107892  612    hrtime    S       pts/0    0:00  sleep 3601
$ kill -9 6114 6115
$ ps l
F   UID   PID  PPID PRI NI      VSZ   RSS   WCHAN  STAT  TTY     TIME  COMMAND
0 1000 3500 3499  20   0 115656   2164  wait       Ss      pts/0   0:00  -bash
4 1000 5093 5092  20   0 115656   2212  wait       S       pts/0   0:00  -bash
[3] 強制終了 sleep 3600
[4]- 強制終了 sleep 3601

実習: stty -a コマンドで、シグナルとキーの割り当てを確認してみましょう。

$ stty -a
speed 9600 baud; rows 29; columns 85; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?;
swtch = ; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc
ixany imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe -echok -echonl -noflsh -xcase -tostop -echoprt echoctl
echoke

11.6 top コマンドと pstree コマンド

ps コマンドの他にプロセスの状態を表示するコマンドとして top コマンドがあります。top コマンドは実行中のプロセスの状態をリアルタイムで表示します。

実習: 実行中のシェルを起点として、プロセスをツリー状に表示してみましょう。

# pstree $$
bash───pstree

topコマンド実行中に「k」キーを実行すると、指定したPIDのプロセスをkillすることが出来ます。
「PID to signal/kill」という表示がされるので、そこにkillしたいプロセスIDを入力する。

# top
top – 02:48:56 up 3 days, 6:29, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 91 total, 2 running, 89 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1017480 total, 703300 free, 113452 used, 200728 buff/cache
KiB Swap: 1040380 total, 1040380 free, 0 used. 761764 avail Mem
PID to signal/kill [default pid = 1] ここに kill したいプロセス ID を入力

11.7 プロセス間通信

Linux 上である処理を完了するのに、1つのプロセスを完結する場合もありますが、複数のプロセスがコミュニケーションを取りながら同期したり、動作を変更して達成する事が多々あります。これをプロセス間通信と呼びます。

次のような特徴があります。

パイプ:1つのプロセスの標準出力をつなぎ替えます。パイプ( | )の左側のコマンド(プロセス)の標準出力を右側のコマンド(プロセス)の標準入力につなぐ事で、通信を実現します。

シグナル:特定のシグナルの受信を待って特定の処理を開始するなど、同期を実現します。

共有メモリ( shared memory ):特定のメモリ領域を複数のプロセスで共有する事でメッセージの受け渡し等が行えます。

セマフォ( semaphore ):資源のロックを行い、複数のプロセス間で同時に書き込みしたりしないように排他処理を実現します。

メッセージキュー( message queue ):キューにメッセージを格納しておき、複数のプロセス間での非同期の通信を実現します。

ソケット:ネットワーク経由のホスト間のプロセスでの通信を実現します。

11.8 章末テスト

(1)作成中のプログラムをシェルプロンプトから実行したところ、プロンプトが返って来なくなった。どのような対処方法があるか。

(2)シグナル番号とシグナル名の組み合わせとして正しいのは次のうちどれか。

  1. SIGINT:1, SIGHUP:2, SIGTERM:9, SIGKILL:15
  2. SIGHUP:1, SIGINT:2, SIGTERM:9, SIGKILL:15
  3. SIGHUP:1, SIGINT:2, SIGKILL:9, SIGTERM:15
  4. SIGHUP:1, SIGINT:2, SIGTERM:9, SIGKILL:15
Linux標準教科書リンク画像

Linux標準教科書より抜粋

章末テスト解答

(1)強制的にCtrl + cで抜けます。PID(調べて)をKillします。

# ps -l
# kill -9 (PID番号)

(2)3

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください