作業系統抽象與網路 (OS Abstractions & Networks)
Overview Table
| 小節 | 主題 | 核心概念 | 一句話重點 |
|---|---|---|---|
| 1.7 (p.50-51) | OS 管理硬體 | layered view、三大抽象 | 應用程式操作硬體一律必須經過 OS |
| 1.7.1 (p.51-53) | Processes | process、context switch、system call、kernel | process 是「執行中程式」的 OS 抽象,提供獨占硬體的假象 |
| 1.7.2 (p.53) | Threads | thread、共享 code/global data | 一個 process 內的多個執行單元,共享資料比跨 process 容易 |
| 1.7.3 (p.54-55) | Virtual Memory | virtual address space、五大區域 | 每個 process 有相同、統一的記憶體視圖 |
| 1.7.4 (p.55) | Files | file = byte sequence、Unix I/O | 所有 I/O 裝置都建模成檔案 |
| 1.8 (p.55-57) | Networks | 網路 = 另一個 I/O device、client-server | 跨機器複製資料是現代系統最重要用途之一 |
| 1.9 開頭 (p.58) | Important Themes | Amdahl's law 引入 | 系統 = 硬體 + 系統軟體交織合作;詳見 01-Computer-Systems-Tour/04-Amdahls-Law-and-Concurrency-Themes |
1.7 作業系統管理硬體 (The OS Manages the Hardware) (p.50-51)
回到 hello 範例:shell 載入並執行 hello、hello 印出訊息時,兩者都不曾直接存取 keyboard、display、disk 或 main memory,而是依賴 operating system 提供的服務。OS 是一層插在應用程式與硬體之間的軟體,應用程式對硬體的所有操作都必須經過 OS(Figure 1.10)。
┌────────────────────────────────────────┐
│ Application programs │ ┐
├────────────────────────────────────────┤ ├ Software
│ Operating system │ ┘
├─────────────┬──────────────┬───────────┤
│ Processor │ Main memory │ I/O devices│ ─ Hardware
└─────────────┴──────────────┴───────────┘
Figure 1.10 電腦系統的分層視圖
OS 的兩大目的:
- 保護硬體:防止失控 (runaway) 的應用程式濫用硬體。
- 提供簡單一致的機制:讓應用程式操作複雜且差異極大的低階硬體裝置。
OS 透過三個基本抽象 (fundamental abstractions) 同時達成兩個目標(Figure 1.11),抽象層層包含:
┌───────────────────────────────────────────┐
│ Processes │
│ ┌───────────────────────────────────┐ │
│ │ Virtual memory │ │
│ │ ┌──────────────────┐ │ │
│ │ │ Files │ │ │
│ │ └──────────────────┘ │ │
│ └───────────────────────────────────┘ │
└───────────────────────────────────────────┘
Processor Main memory I/O devices
Figure 1.11 OS 提供的抽象與其涵蓋的硬體
| 抽象 | 抽象化的硬體對象 |
|---|---|
| Files | I/O devices |
| Virtual memory | Main memory + disk(I/O devices) |
| Processes | Processor + main memory + I/O devices |
這張對應表是經典考點:process 涵蓋範圍最大(處理器、記憶體、I/O 全包),virtual memory 次之(記憶體 + 磁碟),file 最小(只抽象 I/O 裝置)。
1.7.1 行程 (Processes) (p.51-53)
Process 是 OS 對「執行中程式 (running program)」的抽象——電腦科學最重要且成功的想法之一。它提供三重假象 (illusion):程式彷彿是系統上唯一執行的程式、獨占 processor / main memory / I/O devices;processor 彷彿不被中斷地逐一執行指令;程式的 code 與 data 彷彿是記憶體中唯一的物件。
- 多個 process 可在同一系統上並行 (concurrently) 執行:一個 process 的指令與另一個 process 的指令交錯 (interleaved)。
- 多數系統中,待執行的 process 數量多於 CPU 數量。傳統系統一次只能執行一個程式;multi-core 處理器可同時執行多個(1.9.2 節再談)。
- 單一 CPU 靠 context switching 在 process 間切換,製造並行假象。
Context(上下文):process 執行所需的全部狀態資訊,包括 PC 目前值、register file、main memory 內容。OS 決定轉移控制權時執行 context switch:
- 儲存 (save) 目前 process 的 context
- 還原 (restore) 新 process 的 context
- 把控制權交給新 process —— 新 process 從它上次停下的地方精確地繼續
Time Process A Process B
│ ┌─ User code
│ │ ┐
read └─ Kernel code ──────┐ ├ Context switch
│ ▼ ┘
│ User code
│ Disk interrupt │ ┐
│ ┌─ Kernel code ◀─────┘ ├ Context switch
Return└─ User code ┘
from read
▼
Figure 1.12 Process context switching(hello 情境)
hello 情境中有兩個並行 process:shell process 與 hello process。流程:shell 等待命令列輸入 → 使用者要求執行 hello → shell 呼叫 system call 把控制權交給 OS → OS 儲存 shell 的 context、建立新的 hello process 及其 context、把控制權交給 hello → hello 終止後,OS 還原 shell 的 context 並交回控制權,shell 繼續等待下一個指令。
Kernel(核心):
- OS 中常駐記憶體 (always resident in memory) 的那部分程式碼。
- 應用程式需要 OS 動作(如讀寫檔案)時,執行特殊的 system call 指令,把控制權轉給 kernel;kernel 完成操作後返回應用程式。
- kernel 不是一個獨立的 process,而是系統用來管理所有 process 的一組 code 與 data structures。
易錯:kernel ≠ process。它是被所有 process 共用的程式碼與資料結構集合。另外 process 抽象需要低階硬體與 OS 軟體密切合作才能實現,細節見 08-Exceptional-Control-Flow/02-Processes-and-Context-Switches。
1969 年 Bell Labs 的 Ken Thompson、Dennis Ritchie、Doug McIlroy、Joe Ossanna 因 Multics 計畫過於複雜而退出,在 DEC PDP-7 上以機器語言開發更簡單的 OS;階層式檔案系統與「shell 作為 user-level process」的想法皆借自 Multics。1970 年 Brian Kernighan 取名「Unix」(對 Multics 複雜性的雙關嘲諷);1973 年 kernel 以 C 重寫,1974 年對外發表。柏克萊在 1970 末–1980 初加入 virtual memory 與 Internet protocols,推出 4.xBSD;Bell Labs 同期推出 System V。1980 年代中期各家 Unix 互不相容,IEEE 主導標準化,Richard Stallman 命名為「Posix」,涵蓋 system call 的 C 介面、shell 程式與工具、threads、網路程式設計;後與 Standard Unix Specification 合流成單一標準。
1.7.2 執行緒 (Threads) (p.53)
現代系統中一個 process 可由多個執行單元組成,稱為 thread;每個 thread 都在該 process 的 context 中執行,共享同一份 code 與 global data。
Thread 日益重要的三個原因(教科書原列):
- 網路伺服器對並行 (concurrency) 的需求。
- 多 thread 之間共享資料比多 process 之間更容易。
- thread 通常比 process 更有效率。
多執行緒 (multi-threading) 也是多處理器可用時讓程式跑更快的方法之一(1.9.2 節;實作見 Chapter 12)。
| 比較 | Process | Thread |
|---|---|---|
| 定義 | 執行中程式的 OS 抽象 | process 內的執行單元 |
| code / global data | 各自獨立(獨占假象) | 同一 process 內共享 |
| 資料共享難度 | 較難 | 較容易 |
| 切換/建立成本 | 較高 | 通常較低(更有效率) |
1.7.3 虛擬記憶體 (Virtual Memory) (p.54-55)
Virtual memory 提供每個 process「獨占 main memory」的假象。每個 process 看到相同、統一的記憶體視圖,稱為 virtual address space。Linux 的佈局如 Figure 1.13(其他 Unix 類似);位址由下往上遞增,最頂端區域保留給所有 process 共通的 OS code 與 data,下方才是使用者 process 的 code 與 data。
高位址
┌──────────────────────────────┐
│ Kernel virtual memory │ ← user code 不可見/不可存取
├──────────────────────────────┤
│ User stack │ ← run time 建立;函式呼叫時
│ (created at run time) ↓ │ 向下成長,return 時收縮
├──────────────────────────────┤
│ ... │
│ Memory-mapped region for │ ← 例:printf 所在的
│ shared libraries │ C standard library
│ ... │
├──────────────────────────────┤
│ ↑ │
│ Run-time heap │ ← malloc/free 動態伸縮
│ (created by malloc) │
├──────────────────────────────┤
│ Read/write data │ ┐ 由 hello 執行檔
├──────────────────────────────┤ ├ (executable object file)
│ Read-only code and data │ ┘ 直接初始化載入
├──────────────────────────────┤ ← program start(固定位址)
│ │
└──────────────────────────────┘ 0
低位址
Figure 1.13 Linux process 的 virtual address space
由低位址往高位址的五個區域:
| 區域 | 何時建立/如何變化 | 相關章節 |
|---|---|---|
| Program code and data | 所有 process 的 code 從同一固定位址開始;之後是對應 global C variables 的 data;由 executable object file 直接初始化,大小固定 | Ch.7 linking/loading |
| Heap | 緊跟 code/data 之後;malloc / free 呼叫使其於執行期動態擴張與收縮 |
Ch.9 |
| Shared libraries | 位於位址空間中段;存放 C standard library、math library 等共享函式庫的 code 與 data | Ch.7 dynamic linking |
| Stack (user stack) | 位於使用者位址空間頂端;compiler 用它實作函式呼叫;呼叫函式時成長、return 時收縮 | Ch.3 |
| Kernel virtual memory | 位址空間最頂端,保留給 kernel;應用程式不得讀寫此區內容、不得直接呼叫 kernel 函式,必須透過 system call 請 kernel 代為執行 | Ch.8/9 |
Virtual memory 的運作需要硬體與 OS 軟體的精密互動,包括處理器產生的每一個位址都要做硬體轉譯 (hardware translation)。基本想法:把 process 的 virtual memory 內容存在 disk 上,用 main memory 作為 disk 的 cache(詳見 09-Virtual-Memory/01-Address-Spaces-and-VM-Caching)。
「code 從同一固定位址開始」是本章的簡化說法;實務上還有 ASLR 等安全機制會隨機化佈局,見 03-Machine-Level-Programs/06-Buffer-Overflow-and-Pointer-Safety。另外圖中各區域未按比例繪製。
1.7.4 檔案 (Files) (p.55)
A file is a sequence of bytes, nothing more and nothing less.(檔案就是位元組序列,不多也不少。)
- 每一個 I/O 裝置——disk、keyboard、display、甚至 network——都被建模成 file。
- 系統中所有輸入輸出都透過讀寫檔案完成,使用一小組稱為 Unix I/O 的 system calls。
- 威力來源:給應用程式一個統一的視圖 (uniform view) 面對各式各樣的 I/O 裝置——操作磁碟檔案的程式設計師完全不需知道底層磁碟技術,同一支程式可在使用不同磁碟技術的系統上執行(詳見 10-System-IO/01-Unix-IO-and-Files)。
1991 年 8 月,芬蘭研究生 Linus Torvalds 在 comp.os.minix 上低調宣布一個「(free) operating system (just a hobby, won't be big and professional like gnu)」,目標是 386(486) AT clones;起點是 Tanenbaum 為教學開發的 Minix。Linux 之後與 GNU 專案結合,發展成完整、Posix-compliant 的 Unix 系統(kernel + 全部支援基礎設施),可在從手持裝置到大型主機的各種電腦上執行。
1.8 系統利用網路與其他系統溝通 (p.55-57)
至此我們把系統當成孤立的軟硬體集合;實務上現代系統常以網路連結其他系統。從單一系統的觀點,網路只是另一個 I/O 裝置(Figure 1.14):
CPU chip
┌─────────────────┐
│ Register file │
│ PC ──── ALU │
└───────┬─────────┘ System bus Memory bus
Bus interface ◀══════════▶ I/O bridge ◀═════▶ Main memory
║
═══════════╬════════════════════ I/O bus
║ ║ ║ ║
USB Graphics Disk Network
controller adapter controller adapter
│ │ │ │
Mouse/Keyboard Monitor Disk Network ←── 通往其他機器
Figure 1.14 網路是另一個 I/O device
- 系統把一串 bytes 從 main memory 複製到 network adapter 時,資料流過網路到另一台機器(而不是流向本地磁碟)。
- 反向亦然:系統可讀取其他機器送來的資料並複製進自己的 main memory。
- 有了 Internet 這類全球網路,在機器間複製資訊成為電腦系統最重要的用途之一——email、instant messaging、World Wide Web、FTP、telnet 都建立在「跨網路複製資訊」的能力上。
telnet 遠端執行 hello 的五個步驟(Figure 1.15)——典型的 client-server 交換:
(1) 使用者在鍵盤 (2) client 送 "hello" 字串給 telnet server
輸入 "hello" ─────────────────────────────────▶
┌──────────┐ network ┌──────────┐
│ Local │ │ Remote │ (3) server 把 "hello" 交給
│ telnet │ │ telnet │ shell;shell 執行 hello
│ client │ │ server │ 程式,輸出交回 server
└──────────┘ ◀───────────────────── └──────────┘
(5) client 在顯示器印出 (4) server 把 "hello, world\n"
"hello, world\n" 字串送回 client
Figure 1.15 用 telnet 跨網路遠端執行 hello
- 使用者在鍵盤輸入
hello並按 enter。 - telnet client 把字串經網路送給 telnet server。
- server 收到後轉交遠端 shell;shell 執行
hello程式,把輸出行交回 telnet server。 - server 把輸出字串
hello, world\n經網路轉送回 client。 - client 在本地終端機印出該字串。
這種 client 與 server 間的交換是所有網路應用的典型模式(建構網路應用與 Web server 見 11-Network-Programming/01-Client-Server-Model-and-Networks)。
1.9 重要主題(開頭,p.58)
本頁開啟 1.9 節:系統不只是硬體,而是硬體與系統軟體交織、必須合作才能執行應用程式的集合體。p.58 並引入 Amdahl's law——加速系統的某一部分時,整體效益取決於該部分的佔比 α 與加速倍率 k:
例:α = 0.6、k = 3 → S = 1/[0.4 + 0.6/3] = 1.67×。主要洞見:想大幅加速整個系統,必須改善佔整體很大比例的部分。完整討論(含極限情況 k→∞、並行主題)見 01-Computer-Systems-Tour/04-Amdahls-Law-and-Concurrency-Themes。
Exam/Test Patterns
| 情境 / 關鍵字 | 答案 |
|---|---|
| OS 的兩大目的? | (1) 保護硬體不被失控應用程式濫用;(2) 提供簡單一致的機制操作複雜多樣的低階硬體 |
| files / virtual memory / processes 各抽象什麼硬體? | files → I/O devices;virtual memory → main memory + disk;processes → processor + main memory + I/O devices |
| 「並行 (concurrently)」在 1.7.1 的定義 | 一個 process 的指令與另一個 process 的指令交錯 (interleaved) 執行 |
| context 包含哪些狀態? | PC 目前值、register file、main memory 內容 |
| context switch 三步驟 | 儲存目前 process 的 context → 還原新 process 的 context → 把控制權交給新 process |
| kernel 是不是一個 process? | 不是;它是常駐記憶體、用來管理所有 process 的 code 與 data structures 集合 |
| 應用程式如何請 OS 做事? | 執行 system call 指令,把控制權轉給 kernel;kernel 完成後返回 |
| thread 與 process 共享關係 | 同一 process 的 threads 共享該 process 的 code 與 global data |
| 為何 thread 越來越重要?(三理由) | 網路伺服器需要並行;threads 間共享資料較容易;threads 通常比 processes 更有效率 |
| virtual address space 由低到高五區 | program code and data → heap → shared libraries → user stack → kernel virtual memory |
| 哪些區域執行期動態伸縮? | heap(malloc/free)與 user stack(函式呼叫/返回);code/data 區在 process 開始後大小固定 |
| virtual memory 的基本想法 | process 的 virtual memory 內容存於 disk,main memory 作為 disk 的 cache;每個位址都經硬體轉譯 |
| file 的定義 | a sequence of bytes, nothing more and nothing less;所有 I/O 透過 Unix I/O system calls 讀寫檔案 |
| 從單一系統看,網路是什麼? | 另一個 I/O device(透過 network adapter 收送 bytes) |
| telnet 遠端執行 hello 的步驟排序 | 輸入 → client 送字串 → server 交給 shell 執行 → server 送回輸出 → client 印出 |
| Unix 名稱由來 / kernel 何時改用 C | Brian Kernighan 1970 年取名(嘲諷 Multics);1973 年 kernel 以 C 重寫 |
| Posix 標準涵蓋什麼? | Unix system calls 的 C 介面、shell 程式與工具、threads、網路程式設計 |
| α=0.6、k=3 的 speedup? | S = 1/[(1−0.6)+0.6/3] = 1.67× |
Related Notes
- 01-Computer-Systems-Tour/02-Hardware-Organization-and-Program-Execution — 前置:hello 在硬體上的執行、bus/I/O 結構(Figure 1.14 的基礎)
- 01-Computer-Systems-Tour/01-Information-and-Program-Translation — hello 程式的來源與編譯系統
- 01-Computer-Systems-Tour/04-Amdahls-Law-and-Concurrency-Themes — 接續 1.9:Amdahl's law、並行與抽象主題
- 08-Exceptional-Control-Flow/02-Processes-and-Context-Switches — process 與 context switch 的完整機制
- 09-Virtual-Memory/01-Address-Spaces-and-VM-Caching — virtual address space 與「main memory 作為 disk 的 cache」細節
- 10-System-IO/01-Unix-IO-and-Files — Unix I/O 與檔案抽象的實作
- 11-Network-Programming/01-Client-Server-Model-and-Networks — client-server 模型與網路程式設計
- 12-Concurrent-Programming/02-Threads — threads 程式設計模型