多工環境
何謂程序? (特別與 「程式」 對照)
程式 program 是一個靜態的東西, 通常指放在硬碟 (或光碟, 或其他儲存裝置) 上面的檔案。 有時候會以 程式原始碼 program source code 或 可執行檔 executable 來更明確地區分程式的兩種狀態 -- 前者是給人讀/寫的版本; 後者是經過 編譯, 給機器執行的版本。 當然如果一個程式以某種 直譯語言 interpreted language 寫成, 就沒有這個分別了, 同樣一個檔案, 既可以給人讀寫, 也可以給機器執行。 現今的 命令稿語言 scripting language 如 shell script, perl, python, php, ... 等等, 均屬此類。
程序 process 則是一個動態的東西, 可以說是 "執行中的程式 (program in execution), 它的生命從載入記憶體, CPU 開始執行起, 到最後一個指令被 CPU 執行結束為止。
通常程序的壽命相形較短, 只存在於電腦開機的時刻; 而程式則不然。 又, 一個程式可能產生好幾個程序 -- 例如上網頁製作課時, 老師一聲令下, 許多同學先後打開同一個程式 nvu。 一個程序也可能先後執行好幾個不同的程式, 例如本頁中使用 exec 的實驗。
操作範例
- 下
ps
命令並注意 "命令欄" (command), 可以看到有兩個 processes (程序) 正在執行: 一個是 bash (或 tcsh); 另一個是 ps. - 下
ps -f
命令並注意 "狀態欄" (status): 先前一直在接受你輸入命令列的 shell 程序正在睡覺 (sleep); 而剛剛叫出來執行的 ps 程序則正在跑 (running). - 注意上面的 pid 與 ppid (parent process id). 再下一次
ps -f
命令, 再看看它們的 pid 與 ppid: 你的 shell 還是同一個 process; 而 ps 則是另一個新的 process. 但不論是先前的 ps 或是現在的 ps, 都是從你的 shell 給 fork 出來的 (它們共同的 parent process 都是你的 shell). -
接下來不要 logout, 另外再開啟一個 terminal:
- 如果你在 X-Window 下, 就開啟一個新的 rxvt 或 xterm;
- 如果你在 Linux 的文字模式下, 就用 <Alt>-F2 或 <Alt>-F3 或 <Alt>-F6 切換到另一個 virtual terminal (虛擬終端機) 去.
- 如果你在 MS Windows 下透過網路連到 UNIX 主機, 就再開一個 putty 或 telnet.
- 在這個新的 terminal 下, 下
ps
命令, 結果還是看到兩個 processes. 結論: 平時 ps 只顯示在同一個 terminal 內執行的所有 processes. 如何一次看到自己所有的 processes, 不論這些 processes 在那個 terminal 下執行, 甚或不在任何一個 terminal 下執行? 用ps x
. Q: 為什麼只看到 3 個, 而不是 4 個? 猜猜看: 如果你開啟第三個 terminal, 再在其中任何一個 terminal 內下ps x
, 會看到那幾個 processes? (你應該可以猜得到其中幾個的 pid.) - Q: 在一個 terminal 下用 nano 編輯一個檔案, 在第二個 terminal 下用 less 看另一個檔案, 在第三個 terminal 下用 ps x 看看有那些 processes 在執行. 請指出每個 pid 所代表的 process 各在做什麼事情.
- 如何查看系統內所有的 processes? 下
ps -A
命令. 可是那些是我的, 那些是別人的呢? 下ps -Af
命令. (我最常用這個組合) - 查看系統內所有 processes 的父子關係:
ps -Af --forest | less
- 準備動作: 把 sysinfo 存檔, 並把執行的權限開放給自己. 執行 ./sysinfo 這是一個文字模式下的電子鐘; 同時還會印出系統內目前總共有多少個程序在執行.
- 如何打斷正在執行的 process? 按 ^C.
- 把一個命令丟到背景去執行:
sysinfo &
雖然很明顯地, sysinfo 開始執行了; 但是請注意 command prompt 又跑出來了. 這表示你可以繼續下命令, 例如ls
或是last | less
等等. (題外話: sysinfo 使用 ANSI Escape Sequence 來移動遊標, 所以它的輸出可以固定在右上角, 不過這和 process 的觀念無關) 你在 shell 底下繼續執行的叫做 前景 job (foreground job); sysinfo 叫做 背景 job (background job) - 再丟一個背景 job 吧:
sysinfo 3 &
這次新的 sysinfo 顯示在第三列. (而原來的 sysinfo 還是在第一列繼續執行.) - 看一下現在有那些背景 jobs 在執行:
jobs
- 也用
ps l
看一下有那些 processes 正在執行. 目前可以把 job 和 process 想成是同一個東西 -- 就是一個正在執行的程式.jobs
命令只顯示在背景執行, 或處於 "凍結" 狀態的 processes; 而ps
則連正在前景執行的也會顯示. - 一次把兩個背景 jobs 都終結掉:
kill %1 %2
然後用jobs
再檢查一下. - 這一次在前景執行:
sysinfo
然後按 ^Z 鍵把正在執行的前景 job "凍結" (suspend) 起來, 再用jobs
看看所有背景 job 的狀態, 最後用 bg %1 指令把 1 號 job 丟到背景去執行, 並用 jobs 檢查結果. - 如果有好幾個 processes 同時在跑, 那麼鍵盤輸入的資料究竟會被那個 process 讀進去呢? 當然就是那個正在前景執行 (用 jobs 看不到, 用 ps 才看得到) 的 process 嘍. 如果它搶得鍵盤輸入, 卻又不用, 那麼就會像剛才最開始直接在前景執行 sysinfo 一樣, 對一般鍵沒有反應.
- 接下來用
fg %1
指令把 1 號背景 job 帶到前景執行. (所以沒有 command prompt 出來) 如果沒有問題, 就再用 ^Z 把它凍結起來. - 我們可以用 kill 命令達到相同的效果:
- 再來先用
kill -CONT %1
叫 (目前處於 suspended 狀態的) 1 號 job 在背景繼續執行 (效果和 bg %1 一樣). - 用
kill -STOP %1
凍結 (正在背景執行的) 1 號 job. - 用
kill -TERM %1
打斷 1 號 job. (其實用kill %1
就可以了.) - 有些程式非常頑強, 無法用 ^C 中斷, 怎麼辦? 可以開啟另外一個
terminal, 用
ps x
看, 再用 kill 命令把它打斷. 如果 kill -TERM 還沒有辦法, 可以用 kill -KILL. -
先前的終端機全部關掉. 重開一個終端機, 執行
echo $SHLVL
看一下目前的 shell 是第幾層, 並執行ps l
看看有那些 processes 在執行, 然後下bash
以進入另外一個 shell, 再執行echo $SHLVL
與ps l
. 可以看到原來的 shell 為了等現在的 shell 執行完畢所以在睡覺; 現在的 shell 為了等 ps 所以在睡覺. 按一次 ctrl-d 結束目前的 shell, 再看看目前的 shell 層次, 及有那些 processes 在執行. 最後再按一次 ctrl-d 脫離最開始的 shell. - 同樣重開一個終端機, 執行
echo $SHLVL
與ps l
接著下exec bash
再看看目前的 shell 層次與正在執行的 processes. 注意到現在只有一個 shell, 它的 pid 和原來的 shell 一樣, 而原來的 shell 不見了! 原來的 shell 變身為 bash 了. 現在只要按一次 ctrl-d 就會離開 linux.
名詞解釋
- process (程序): 一個正在執行的程式. 一個可執行檔可以產生好幾個 processes. 例如一個使用者可以同時開啟好幾個終端機視窗, 每個視窗都是一個獨立執行的 process, 但是它們共用 /bin/bash 這一個可執行檔.
- 每個 process 都有一個識別代號 pid (process identification).
- 每個 process 都有一個 parent, 當初這個 process 之所以會產生, 就是由它的 parent process 分出來的. 從一個 process 分出另一個 process 的步驟叫做 fork, 可以想成是無性生殖.
- 但是生出一個與原 process 一模一樣的東西有什麼用呢? 通常 child process 馬上會變身 (exec) 成為另外一個應用程式.
- terminal 或稱 tty (終端機): 大約可以這樣理解: 每個文字視窗就是一個 tty
-
ps l 指令結果各重要欄位意義:
- STAT: 狀態, S (休眠), R (正在跑), I (閑置), T(凍結)
- UID: 這個 process 以那個使用者的名義在執行?
- PID: Process IDentification #, 程序的編號.
- PPID: Parent Process IDentification #, 父程序的編號.
- TTY: 使用的控制終端機.
- TIME: 使用了幾秒鐘的 CPU 時間
- COMMAND: 先前是甚麼樣的命令產生這個程序的?
-
ps 指令常用的參數:
- a: 不只使用者自己的, 連別人的程序也顯示出來.
- u: 對每個程序多顯示 "USER" 這個欄位.
- x: 不只有控制台的, 連沒有控制台機的程序也顯示出來.
- w: 不要把後面切掉啦!
- v, m: 多一些記憶體使用狀況報告
- job (工作?):
-
控制程序執行的一些方法:
- 用 & 把程序丟到背景去執行
- 用 ^C 把執行到一半的前景程序打斷 (無法恢復)
- 用 ^Z 把執行到一半的前景程序暫停
- jobs: 看看這個控制台有那些暫停或在背景執行的程序
- fg %數字: 把某個暫停的程序放到前景來執行
- bg %數字: 把某個暫停的程序放到背景去執行 (和當初直接用 & 的效果相同)
-
送信號給正在執行的程式: kill -TERM pid1 pid2 ...
常用的信號:- TERM (kill 命令的內定值): 警告性地通知程序該中斷了. 寫得好的程式會自己 "清場"
- STOP: 凍結 (正在背景執行的) 程序.
- CONT: 把原本被凍結的程序解凍, 丟到背景繼續執行.
- KILL: 強迫中斷程式, 大部分頑強的程序都會被中斷.
- HUP: 通常用來強迫 demon 類程序重新讀它的設定檔 (組態檔)
- 本頁最新版網址: https://frdm.cyut.edu.tw/~ckhung/b/gnu/process.php; 您所看到的版本: November 20 2017 15:17:08.
- 作者: 朝陽科技大學 資訊管理系 洪朝貴
- 寶貝你我的地球, 請 減少列印, 多用背面, 丟棄時做垃圾分類。
- 本文件以 Creative Commons Attribution-ShareAlike License 或以 Free Document License 方式公開授權大眾自由複製/修改/散佈。