National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 78 24°C PM2.5 18
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 02

行程與狀態

一支程式跑起來之後是什麼:位址空間、PCB、狀態與內容切換
Interaction 25 minute(s)

Learning Objectives

  • 區分程式與行程,說出核心要為一個行程記住哪些資料
  • 說明五種行程狀態與它們之間的轉換,以及 ready 和 blocked 的差別
  • 舉出行程會被阻塞的原因,並說明阻塞的行程不佔用 CPU
  • 說明內容切換保存了什麼,代價在哪裡

同一支程式開兩次,就是兩個行程

開兩個終端機視窗,或把同一個瀏覽器開兩次,磁碟上的程式檔案只有一個,電腦裡卻有兩個互不相干的東西在跑:一個當掉,另一個還在;它們記憶體裡的資料也不同。

程式(program) 行程(process)
是什麼 磁碟上的檔案,內容是指令與初始資料 一支程式跑起來之後的實體
狀態 不會動 有目前執行到哪一行、記憶體裡的值、開著的檔案
數量 一個檔案 同一個檔案可以同時有很多個

核心給每個行程一個編號(pid,process ID),並且讓每個行程都以為自己獨佔一套東西:

  • 位址空間:行程看到的記憶體。不同行程看到同一個位址,內容可以完全不同。
  • CPU:其實是輪流用,但行程感覺不到自己被暫停過。

下面這支程式在真正的 Linux 上列出系統裡所有行程。Linux 的 /proc 是核心提供的虛擬目錄,每個行程一個子目錄,ps 這類工具就是讀這裡:

PID   STATE  COMMAND
1     S      dumb-init
2     R      output.s

在真正的 Linux 上實際執行的結果(Compiler Explorer 的 Linux x86-64 環境,gcc 13.3,2026-11-04)。

這個環境是個小容器,只有兩個行程:負責啟動的 dumb-init 和這支程式自己(編譯出來的執行檔叫 output.s)。在你自己的 Linux 或 WSL 上,用 ps -eo pid,ppid,stat,comm 會看到幾十到幾百個。

互動練習:一支程式,兩個行程輪流跑

fork() 會建立第二個行程,下一課會細講,現在只要知道它讓同一支程式變成兩個行程在跑;wait(NULL) 是等子行程結束。排程先設成「輪轉」:每個行程跑幾個指令就換下一個。

看左邊的卡片:同一時間只有一張是「執行中」,其他是「就緒」。上面的統計列有「內容切換」次數。切到「行程樹」面板可以看到父子關係。

PCB:核心替每個行程記的資料

行程被暫停時,核心要記得所有東西,之後才接得回來。這份資料叫行程控制區塊(process control block,PCB)。Linux 裡對應的資料結構叫 task_struct。

PCB 裡的資料 用途 在 os-lab 哪裡看
pid、父行程 pid 辨識行程、維持親子關係 卡片標題、「行程樹」面板
狀態 就緒、執行中、等待中 卡片上的標籤
暫存器、程式計數器 暫停時 CPU 的內容,恢復時放回去 卡片上的「暫存器」與第幾行
記憶體資訊(頁表) 這個行程的位址空間 「記憶體」面板
開啟的檔案(fd 表) 第 4 課 「檔案與 fd」面板
訊號的處理方式 第 4 課
排程資訊 優先權、用了多少 CPU,第 5、6 課 統計列

Linux 把一部分 PCB 的內容透過 /proc/<pid>/status 給你看。下面在真正的 Linux 上讀自己的狀態,然後睡 5 次,再讀一次:

Name:   output.s
State:  R (running)
Pid:    2
PPid:   1
VmRSS:      1416 kB
Threads:    1
voluntary_ctxt_switches:    0
nonvoluntary_ctxt_switches: 0
--- 睡 5 次之後 ---
Name:   output.s
State:  R (running)
Pid:    2
PPid:   1
VmRSS:      1548 kB
Threads:    1
voluntary_ctxt_switches:    5
nonvoluntary_ctxt_switches: 0

在真正的 Linux 上實際執行的結果(Compiler Explorer 的 Linux x86-64 環境,gcc 13.3,2026-11-04)。

最後兩行是這個行程到目前為止的內容切換次數。voluntary 是自己讓出 CPU(例如等待 I/O、睡眠),nonvoluntary 是被核心換下來(例如時間片用完)。睡 5 次,voluntary 剛好多 5。State 是 R,因為它讀這個檔案的時候正在執行。

五種狀態

教科書常用五種狀態描述行程的一生:

狀態 意思
新建(new) 正在建立,還不能跑
就緒(ready) 可以跑,只是還沒輪到 CPU
執行(running) 正在 CPU 上跑。一顆核心同時只有一個
等待(waiting,也叫 blocked) 在等某件事,給它 CPU 也沒用
結束(terminated) 跑完了,等著被清理

這張圖最重要的地方,是等待的行程在事情發生之後會回到就緒排隊,不會直接回到執行,因為 CPU 可能正有別人在用。

ready 和 blocked 是最容易混淆的一對。 就緒的行程想要 CPU,只差排隊;等待中的行程不要 CPU,它缺的是別的東西。排程器只會從就緒的行程裡挑。

互動練習:讓行程在五種狀態之間移動

先在「選行程」點一個行程,再按下面的事件,看它在狀態圖上怎麼移動。試試看能不能把還在等待的行程直接分派 CPU,看看為什麼會被拒絕。

行程在等什麼

常見的阻塞原因:

行程做了什麼 在等什麼 誰叫醒它
sleep(2) 時間到 計時器中斷
read 檔案或網路 資料送到 磁碟或網卡的中斷
read 管線 另一個行程寫入資料 寫入資料的那個行程
wait 子行程結束 子行程結束時由核心通知
pthread_mutex_lock(第 8、9 課) 別人放開鎖 放開鎖的執行緒

共同點是等的東西不在 CPU 上,所以行程把 CPU 讓出來。一支程式花在等待的時間可能遠多於計算的時間,例如文字編輯器大部分時間都在等你按鍵。多工因此才划算:一個行程等硬碟時,別的行程可以用 CPU。

在 Linux 的 ps 裡,狀態用一個字母表示(這些字母和上面五種狀態不是一對一):

字母 意思
R 正在跑或可以跑:包含教科書的「執行」與「就緒」
S 可以被訊號打斷的睡眠:大部分在等事件的行程
D 不可打斷的睡眠,通常在等 I/O
T 被工作控制的訊號停住(例如按 Ctrl+Z)
Z 殭屍:已經結束,父行程還沒來收(下一課)

所以 ps 看到很多個 R,不代表有那麼多行程同時在 CPU 上。

互動練習:兩個行程都在等,CPU 在做什麼

父行程要從管線(pipe,第 4 課會細講,現在把它當成兩個行程之間的通道)讀一個字,子行程先睡 2 秒才寫入。有兩個行程都能跑時,卡片上會出現「讓它走一步」,由你決定輪到誰。兩張卡片都變成「等待中」時,按「執行一步」讓時間前進。

內容切換存了什麼、代價在哪裡

從行程 A 換到行程 B 叫內容切換(context switch)。觸發的時機有兩種:A 自己進入等待(voluntary),或是計時器中斷讓核心決定換人(nonvoluntary)。

核心要做的事:

  1. 把 A 的暫存器、程式計數器、堆疊指標存進 A 的 PCB。
  2. 把 A 的狀態改成就緒或等待,選出下一個行程 B。
  3. 換到 B 的位址空間(把 CPU 指向 B 的頁表)。
  4. 從 B 的 PCB 放回暫存器與程式計數器,B 從上次停下的地方繼續。

B 完全不知道自己被暫停過,它的暫存器和停下時一模一樣。

代價分兩層:

  • 直接的代價:上面這幾步要執行指令,這段時間沒有人在做有用的計算。
  • 間接的代價:換了位址空間,TLB(位址轉換的快取,第 13 課)的內容用不上;B 的資料也不在 CPU 快取裡。B 剛開始跑的那段時間會比較慢。

所以時間片不能切得太短,否則 CPU 都花在切換上,這個取捨第 5 課會細談。

確認一下

1.

同一支程式執行兩次,產生兩個行程。下面哪一個不是兩者各有一份?

2.

行程 A 呼叫 read 讀硬碟,資料讀完時,A 會變成什麼狀態?

3.

一台單核心電腦,ps 顯示有 4 個行程的狀態是 R。下面哪一個說法正確?

4.

行程 A 跑到一半被換下來,之後怎麼知道要從哪裡繼續?

5.

等 5 秒有兩種寫法:sleep(5),或是寫一個迴圈一直檢查時間。兩者差在哪裡?

第 1 次作答

重點整理

  • 程式是磁碟上的檔案,行程是它跑起來之後的實體;同一支程式可以有很多個行程,各有自己的位址空間與暫存器。
  • 核心用 PCB 記住行程的一切。暫停時把 CPU 的內容存進去,輪到時放回來。
  • 五種狀態裡最關鍵的區別:就緒是在等 CPU,等待是在等別的事;等待結束之後要回到就緒排隊。
  • 內容切換有直接代價,也有快取、TLB 失效的間接代價。

下一課看行程是怎麼來的:fork、exec 和 wait,也就是 Shell 啟動程式的方式。

這一課完成了!
Next lesson:fork、exec 與 wait
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。