作業系統 - 學習筆記 (2) Process
「Program」、「Process」、「Thread」傻傻分不清楚?本文介紹作業系統 Process 的概念。
Program vs. Process vs. Thread
Program
- 靜態的指令集 (file)
- 例如:秘密小文件、週記、Hello world 程式
Process
- 正在執行的指令集,有被載入主記憶體的 Program (executable file)
- 簡而言之,就是正在執行的程式
- 首先會先被傳入 Ready Queue (準備變成 Process 的動作),再來被載入主記憶體、載入 CPU 裡面正在執行
Process 組成架構
- Text:一個 C 語言的程式
- Data:全域變數
- Heap:動態記憶體配置
- Stack:放一些暫存的資料
I/O-bound process
- I/O 的東西使用的比較多
- 例如:Word processor
- CPU bound process
- 需要 CPU 不斷運算的程式
- 例如:算圓周率
- 平常的程式通常是兩個結合起來
Process 狀態及流程
- New:新增一個 Process 出來
- Ready:程式載入記憶體
- Running:正在跑,Process 正在運算
- Waiting:有中斷,進入等待
- Terminated:Process 結束
Thread
- Process 的小分身,寄生在 Process 裡面,共用 Process 的記憶體,且自己也擁有一個獨立的空間 (Stack) 可以做自己的事
- 一定要有 Process 才會有 Thread
- 一個 Process 有好多個 Thread (看 Chrome 就知道)
- 例如:Word 拼音檢查的紅線
- 如果拼音檢查也寫成 Process 的話,Word 的 Process 會先被關掉才能做拼音檢查
PCB (Process Control Block)
- 像是 ER 圖用資料庫存起來,或者像是排球紀錄表,而 OS 管理 Process 所使用的紀錄表,就叫做 PCB
- 幾個重要資訊:
- Process State:上面提到的那五個狀態 (e.g. new, ready, etc.)
- Process Number:Process 的 ID
- Process Counter:記錄下一個 Process 的位址
- CPU Registers:紀錄一些中斷資訊
排程器
長程排程器 (Long-Term Scheduler)
- 不一定每個 OS 都有
- 看哪個 Process 適合現在載入主記憶體,將它放入 Ready Queue
短程排程器 (Short-Term Scheduler)
- 不管哪個 OS 都一定有
- 因為 CPU 暫存器大小有限,所以會挑選哪些 Process 最適合現在做、最有效率
中程排程器 (Median-Term Scheduler)
- 類似資源短程排程
- 在 Process 載入 CPU 之前,已經通過了長程、短程排程器的篩選,使 CPU 以最有效率的排程完成 Process 們但是,排程的 Process 愈多,Content Switch 轉換的次數就愈多,代表 Drgree of Mutiprogramming 愈高,也就是 CPU 大部分的時間都在做 Content Switch!因此,中程排程器就會在 Drgree of Mutiprogramming 過高的時候,挑選幾個 Process 回到 Ready Queue
- 例如:Content Switch 轉換太頻繁時,100 個工作 1000 秒會完成,其中 CPU 花 500 秒在轉換工作,這對 CPU 來講很沒效率!
這時候就需要中程排程器,把幾個 Process 拉回 Ready Queue
- 例如:Content Switch 轉換太頻繁時,100 個工作 1000 秒會完成,其中 CPU 花 500 秒在轉換工作,這對 CPU 來講很沒效率!
- 以下三個例子都是發生中斷,使 Process 跳回 Ready Queue:
- 需要鍵盤或滑鼠,產生 I/O Request、中斷,先放在 I/O Queue 裡面再逐一使用
- 某一個 Process 使用時間到了,它會先跳回 Ready Queue,再重新分配
- OS 發現其他東西有中斷,做 Context Switch
Context Switch
- 轉換 CPU 至另一個行程。先儲存舊行程的狀態,再載入新行程的狀態
- 例如:A 發生中斷,要把 A Process 的 PCB 表轉換成 B Process 的 PCB 表,才能繼續執行
- 有點類似交接班表
- 花的時間的多寡取決於硬體的快慢
Process 的溝通方式
- 獨立的 Process (Independent Process)
- 獨立不受其他 Process 影響
- 需要溝通的 Process (Cooperating Process)
- 例如:「洗手」這個 Process 必須搭配「開水龍頭」這個 Process 才能達成洗手的動作
- 用 Interprocess Communication (IPC) 溝通
Interprocess Communication (IPC)
- Shared Memory (共享記憶體)
- Process 之間共用一個記憶空間,你的資料就是我的資料,我的資料就是你的資料
- Message Passing (Block send / receive, rendezvous)
- 兩個 Process 中間會多一個 Process Queue (類似郵箱的功能) 暫存,需要的 Process 可以從這裡拿取資料
- 隔開來多一個 Queue 去傳送
- Blocking send:確保一定寄出
- Blocking receive:確保一定收到
- Rendezvous:兩者兼具,確保一定會寄出去,也確保一定會收到
Client-Server 之間 Process 的傳遞
- 以上都是同一台電腦,但是現在網路發達,通常會在不同電腦之間做傳輸
- Socket : IP address (IP 位址) + Port (服務口) = a socket
- 3 種 Socket 方式:
- Connection-Oriented (TCP):確保兩邊都活著,規範嚴謹、動作多、檢查需要時間
- Connectionless (UDP):串流影音、通常需要大量傳遞的
- Muticast Socket (類似廣播):傳播出去讓很多主機連接。
- 使用 Socket 是比較底層、有效率的,通常傳一些位元、字串等比較難懂的東西,一個一個傳
- Remote Procedure Call (RPC)
- 運用在應用層 (最上層) 的服務
- 把需要的東西 (服務) 包起來,傳出去給其他主機,就像是我這台主機本身有另一台主機的東西 (服務)
- 最常見的例子:分散式網路服務、遠端管理、NFS 檔案分享
RPC 傳遞中間會有一些小問題
XDR 轉換
- 不同主機,定義存取 (儲存記憶體) 的方式不同
- Big endian:數字最大的東西放在記憶體位置最大的地方
- 例如:1 儲存在 A;5 儲存在 E
- Small endian:數字最小的東西放在記憶體位置最大的地方
- 例如:1 儲存在 E;5 儲存在 A
- 造成雙方聽不懂、雞同鴨講的問題,因此需要一位翻譯、代理人,也就是 Stub
Stub (proxy)
- 主要就是做 XDR 轉換 (external data representation):轉換 big / small 的部分。
- XDR 的意思是一種通用的格式
- big / small endian 的資料經過 stub 都會轉換成這種大家都看得懂的格式
- stub 轉換成 XDR 送出去的動作是 marshalling
- 翻譯好丟出去 (例如:中翻英,再用英文講出去的這個動作)
- 而 stub 收到 XDR 格式的資料就會依自身主機需求,轉換成 big / small endian (unmarshalling)
- 聽到英文,轉成中文再傳給 Server 聽 (解譯)
- 過去 big endian 比較常見,但現在的作業系統 big 跟 small 兩種都會,比較少出問題了
RPC 在 TCP/IP 傳輸的時候可能會漏掉一些東西,或者多傳了幾次
- 改善的技術
- Exactly once (僅處理一次):一定要剛好傳一次就到
- 資料不能重複,要求 100%,做法較難
- 使用 match maker,類似三方交握的方法
- At most once (最多處理一次):最多傳一次就到
- 一直傳,使用時間戳記 (timestamp) 紀錄,發現時間戳記不對就丟掉,因此資料可能會丟失
- 大部分都是這個方式,因為比較簡單
Pipe
- 仿照硬體 Pipeline 的行為,在 process 之間開一條或數條線來放資料
- 電腦如果要一次做很多工作,會先把動作切成碎片,每個工作輪流做一些、快速切換,讓人看起來是很多工作同時被做
- 有讀取端 (read-end) 與寫入端 (write-end),就叫做 Pipeline
- 輸入 Linux 指令或 CGI 時會看到
- Ordinary Pipe (單向) / Named Pipe (雙向)
Ordinary Pipe
- 兩個 Process 的 f_inode 會指向同一個地方
- f_op 代表這個 process 是要做什麼的
- 有 fd[0] (write end) 跟 fd[1] (read end)
- 步驟:首先有一個人先建管線,假設是 A process 自願建 Pipe 跟 B 連接
- A 的 f_inode 連到 Pipe,此時 A process 的 f_op 有寫入端與讀取端
- A Process 透過 fork() 的動作,複製子 Process (fd[0], fd[1]) 的定義給 B Process
- B 把它的 f_inode 也連起來,此時兩邊都有讀取端與寫入端
- 因為一端只能是讀或是寫,所以 A 把自己的讀取端砍掉,B 把自己的寫入端砍掉,變成 A process 寫給 B Process 去讀取
Named Pipe
- 有一端可以同時是讀 + 寫
以上資源是我自己整理過後的筆記,若有錯誤歡迎隨時和我聯繫。