# 作業系統 CH3 Process ###### tags: `作業系統 Operating System` ## Process Concept Process 與 Program 最主要的差異,在於是否處於執行狀態 - Program (Passive entity) 只是儲存於 ==disk== 中等待被執行的程式碼 - Process (Active entity) 則是位於==記憶體==中的正在被執行的 Program 一個 Process 由以下內容組成: - Code segment (text section) (將 program ==(已編譯為 instruction)== 讀到記憶體中,等待被 CPU fetch 並執行 ) - Data section --> 全域變數 - Stack --> 局部變數以及函數 (方便使用後直接 pop 掉) - Heap --> 動態配置記憶體的變數或是類 (classes) - Current Activity (管理 Process 的 Meta data) --> Program counter, Register Contents - A set of associated resources --> 相關資源的 set,如 Open file handlers (檔案的開啟、或是跟 OS 要某些硬體的控制權) 以下為 Process 執行時記憶體的狀態 ![](https://i.imgur.com/ldTLAwi.png) ## Threads Threads 又稱為 ==`Lightweight process`==,是使用 CPU 的最小單位,同 Process 的 Threads 有共享的記憶體空間。在 Parent Process 創造 Threads 時就會 allocate ,因此省去在空間管理及處理上的執行動作。 - 同 Process 中,Threads 共用以下內容 - code section - data section - OS resources (e.g. open files and signals) - 但以下部份各自獨立 - stack - register set --> 可能 instruction 的執行位置不同,甚至執行不同的 function call - thread ID - program counter ## Process State Process 在其生命週期中,共有 5 個狀態 - New:當 process 被創建時,將 code 讀到記憶體中,並將前述記憶體狀態初始化 - Ready: Process 競爭的資源是 CPU 的核心,管理的方式為佇列 (Queue),在等待被執行的階段,會被放在佇列當中,此狀態稱為 `Ready` - Running:被 CPU 排程選到,執行 instructions。OS 為了確保主控權,一段時間就會將 CPU switch 給 scheduler 而==打斷(interrupt)==程序 - Waiting:有些指令不會直接使用 CPU (如 I/O),因為不需要 CPU ,又需等待某些指令完成,所以進入 Waiting 狀態,待完成後重新放回 Ready - Terminated:Process 完成執行,釋放資源給 OS。 一個 Processor 一次只執行一個 Process ; 但同時可能有多個 Process 處於 Ready 或 Waiting 的狀態。 ![](https://i.imgur.com/2VES9cB.jpg) ## Process Control Block User 創建 Process 後,OS 會自動建立 PCB 來做管理。我們說將 Process 放到佇列當中,指得是將 Process 的 pointer 放到佇列中,而非記憶體空間,使用的資料結構為 `Linked list`。PCB 包含以下內容: - Process state - Program counter - CPU registers 此外還有: - CPU scheduling information - memory management information (base & limit register) --> 只有 process 在執行時才會把這兩個值從 memory load 進 CPU 的 register。 - I/O status/information - accounting information 因為這些資訊只有 OS 需要知道,所以會放在 kernel space 的記憶體空間 ![](https://i.imgur.com/Wq5QtVz.png) ## Context Switch CPU 一次只能執行一個 Process,要切換給另一個 Process 時,必須將舊 Process 的資訊 (e.g. PCB) 儲存起來,並載入新 Process 的資訊,這個動作稱為 「Context Switch」。 CPU 完整切換的流程如下: 1. 執行 P0 2. P0 被打斷讓出 CPU ,此時處於 idle 狀態 3. 進行 Context Switch - 將 P0 的狀態存於 PCB - 並讀取 P1 的 PCB。 - 完成 Context Switch 5. 執行 P1 Context switch 的過程中, CPU 沒有執行任何 instruction,因此 Context Switch 其實是 overhead,浪費 CPU 的資源。但為了 CPU sharing 及 time sharing,Context switch 無法避免地經常發生,所以我們只能盡可能縮短時間: - memory speed - number of registers (越少則存取的次數降低,但現在的系統中為了更快速的計算,register 數量是變多的) - 合併 load & save PCB 的 instruction,讓 CPU 一次做完 - 硬體支援 --> multiple sets of registers,一次記住多個 Process 的狀態,可以快速的在 registers 間進行切換,無須透過 memory access ![](https://i.imgur.com/1UuHI1E.png) ## Process Scheduling - Multiprogramming:多工處理, CPU 可以執行多個 Process,以最大化利用 CPU - Time sharing:分時系統,為一種資源的共享方式,系統可以頻繁地進行 Context Switch,讓多個 User 可以同時使用 Program 由於 Process 共享 CPU,使用的先後順序就是由 scheduler 來決定。 ## Process Scheduling Queue - Job queue (New State): 系統中所有的 Process - Ready queue (Ready State): 在主記憶體中正在及等待執行的 Process - Device queue (Wait State): 等待 I/O 處理的 Process ![](https://i.imgur.com/hrZLweT.png) ## Process Scheduling Diagram ![](https://i.imgur.com/NCCeoZc.png) ## Schedulers Scheduling 分為 CPU 及 Job Scheduling - CPU Scheduling : 因為 time sharing 的原因,發生頻率非常高,又稱為 Short-term scheduler。CPU Scheduler 會選擇該被執行的 Process 並 Load 到 CPU 當中,從 ==Ready State 轉換成 Run State== - Job Scheduling : 可能幾秒或幾分鐘才需要 scheduling,又稱為 Long-term scheduler,通常是使用者人為觸發,新的程式被執行,產生程序時才需要被排程,從 ==New State 轉換成 Ready State== - Medium-term : 跟虛擬記憶體結合產生的一種 scheduler,因為 memory 空間是有限的,有時會將 disk 的空間拿來使用,當 memory 不夠時,就會將部份 Process 從 memory 踢回 disk,這個動作即由 Medium-term scheduler 來處理,由 ==Ready state 轉換為 Wait state== ![](https://i.imgur.com/tFb1So2.png) ### Long-Term Scheduler - 控制在記憶體中 Process 的數量 (degree of multi-programming) - 當 degree 太低時, CPU 有很多的時間在 idle - 當 degree 太高時,會發生 Thrashing,有太多的 Process 在爭搶有限的 memory,導致 Process 一直在 memory 跟 disk 之間 swap,不斷的做 I/O - 因我們希望 CPU 跟 I/O 執行的時間差不多,負載盡可能平衡而最大化系統效能,所以 Process 要能夠在 CPU-Bound & I/O-Bound 良好的混合 - 在 UNIX/NT 系統中,並沒有 Long-Term Scheduler - 直接將 Process 放到 short-term scheduler 中 (現今電腦的記憶體空間通常是足夠的) - Multipropramming degree 受硬體限制 (e.g. # of terminals) 或著由使用者自己調整 ### Short-Term Scheduler - 執行頻率很高,大約 100ms 執行一次 - 由演算法來縮短每個 Process 的等待時間 - 因為效率要高,演算法也不能太過複雜,避免 CPU overhead 過高 - overhead = (time of pick) / (time of execution + time of pick) ![](https://i.imgur.com/Ec849XW.png) ### Medium-Term Schduler 因現代 memory 空間的增長以及虛擬記憶體的觀念引入,過往由 Long-Term Schduler 處理的動作多改由 Medium-Term Schduler 執行 - swap out : 將 Process 由 memory 搬到 disk 中 - swap in : 將 Process 由 disk 搬到 memory 中 - propose : 改善 Process mix / 減少記憶體中的 Process 數量,降低 degree釋放記憶體空間 ![](https://i.imgur.com/szHrx70.png) ## Operations on Processes 回到 programmer 及 user 角度,我們到底如何跟 Process 溝通 ### Tree of Processes - 無論什麼作業系統, Processes 一定可以畫成如下的樹狀結構 - 每一個 Process 由 unique processor identifier (pid) 識別 ![](https://i.imgur.com/3xm9KY5.png) ### Process Creation - 資源之間的關聯性可能如下 - Process 的 Parent 及 Child 共享資源 - Child Process 共享部份 Parent 的資源 - Parent 及 Child 完全不分享資訊 - 兩種可能的執行方式 - Parent 及 Children 同時執行 - Parent 等到 Children 結束後才執行 - 兩種可能的記憶體空間 - Child 為 Parent 的複製 (執行碼、counter 等與 Parent 完全一樣),透過 sharing variable 溝通 (address 不同) - 將特定的 program 丟進 Child 的 code section,重設 counter,讓 Child 變成完全不同狀態的 Process,透過 message passing 溝通 ### UNIX/Linux Process Creation 相關資料: [MIT6.s081 Lab: Xv6 and Unix utilities](https://hackmd.io/@Chang-Chia-Chi/Sy2nHUGtt#find-moderate) - fork system call (Create Process) - 創建新的 (child) process - 該 process 複製其 parent 的記憶體空間 - Child 與 Parent 在 fork 後同時執行 (execution concurrently) - Child 在 fork 的回傳值為 0 - Parent 在 fork 的回傳值為 Child process 的 PID - execlp system call (Reset Process) - 先創建 Process 及 OS 要記憶體空間,並註冊新的 PID - 將新的 binary file 讀入記憶體,並將內容如變數 (heap、stack)、counter 等全部清空 (reset) ,等於讓新的 Child Process 執行不同的程式 - wait system call - 因 Child & Parent 在 Unix 中是 concurrent 執行,若要控制執行的順序,必須用 wait system call,強制 parent 直到其中一個 Child 的 process 完成後才執行 - Memory space of fork() - 舊的實作 Child 為 Parent 的完整複製 - 新的實作使用 `copy-on-wirte` 技術,在 Run time 過程中,儲存 Child 的與 Parent 的不同處 (A's Child 在執行過程中會慢慢增長) - 若 call execlp,則會產生完全獨立的 Child Process (本例中的 C) ![](https://i.imgur.com/gmgKZfX.png) 以下為 UNIX/Linux Process Creation 的範例程式碼 ![](https://i.imgur.com/TqYJBBB.png) 以下範例簡單示意 fork 的特性, Child Process 會保存 fork() 呼叫當下 Parent Process 的狀態。注意如果過程中呼叫 execlp ,則該分支會斷掉,樹不會繼續往下生長 ![](https://i.imgur.com/lQt21em.png) ### Process Termination 當 Process 執行到最後一個指令或是呼叫 exit(),都會中止程序 - 該 Process 所有相關資源,如記憶體空間 (physical, virtual)、I/O buffer、open files 等都會清空並將資源還給 OS - Parent 可利用 PID(abort) 來中止特定 Child Process - 當 Child 配置太多記憶體 - Child Process 執行的任務不再需要 - Cascading termination:因為是樹狀結構,所以當 Parent 被中止,則 Child Process 也會被中止,這也是為什麼 `ctrl+C` 可以強制停止 Process,因為其他程序都是由 console 程序創建,更進階的是呼叫 `kill`,但需要管理者權限 ## Interprocess Communication - 定義:在多個 Process (或 Threads) 間溝通的機制 - 目的: - 資訊的共享 - 加快計算速度 (not always true) - 便利性 (performs several tasks at one time) - modularity (e.g. [micro-kernel](https://en.wikipedia.org/wiki/Microkernel)) ### Communication 要做到 IPC 用 memory 分別有兩種方式 - Shared memory:共用記憶體空間 - 需要小心處理 synchronization - 利用 memory address 實作,好處就是快 - 透過 memory 的 address 存取資料 - Message passing:透過 memory 的 copy,網路或跨電腦的程式通常都是以這種作法溝通 - 沒有 conflict 的問題,但若資料小,用這個方法的話可以省去 share memory 的 lock 之類的額外資源消耗,反而會略快(且不用在意 sync 的問題) - 使用 send/recv message - 以 system call 實作,通常較慢 ### Communication Methods - Sockets - 透過 IP & Port 來 identify 使用者,port number 指得就是 Process - 藉由未結構化的位元資料來溝通 (unstructed stream of bytes) ![](https://i.imgur.com/G3vMXvv.png) - 會有 client & server - server 要先打開 client 才能連 - client 進行 connect 之後,就可以盡情 read / write - 補充: server 在 accept 之後,會動態開 thread,如此才能一次處理多個 request - [Remote Procedure Calls (RPC)](https://en.wikipedia.org/wiki/Remote_procedure_call) - 可以呼叫其他的 Process 甚至其他電腦的 Process - 參數以及回傳值以 message 傳遞 - 與 socket 不同,傳輸的資料是有 data type 的 - Library 通常會有 stubs,在 client 端和 server 端會各有一隻小程式,(server 端的叫 skeleton)會負責 implement 細節 - 其實通常下面也可能用 socket,只是幫 programmer 包起來而已 - [parameter mashaling](https://en.wikipedia.org/wiki/Marshalling_(computer_science)) 把 params 包進 message 且嚴謹的管理。要把兩台電腦串在一起其實有許多細節要處理,RPC 就要負責幫使用者把這些繁瑣的事情解決掉 ![](https://i.imgur.com/JNm5Tcd.png) >In distributed computing, a remote procedure call (RPC) is when a computer program causes a procedure (subroutine) to execute in a different address space (commonly on another computer on a shared network), which is coded as if it were a normal (local) procedure call, without the programmer explicitly coding the details for the remote interaction. ### Shared Memory Process 要能夠 ... - 創建 shared memory 的區塊 - 共享的記憶體區塊通常會在創建 shared memory 的 Process 的附近 - 透過這個 shared memory 溝通的 Processes,要告知 OS 說我要共用這塊記憶體位置 (attach) - 資料格式為 bytes,由 process 自行定義, OS 不處理 - Processes 不能同時對同一塊記憶體做讀寫的動作 ### Consumer & Producer Problem - 兩個 Process 共用一塊 Buffer 記憶體 - Buffer 是大小為 B 的 circular array - 因為 Buffer 有空間限制,必須有以下資訊來控制 - next free: in - first available: out - empty: in = out (out 拿光) - full: (in + 1) % B = out - 這邊為了 sync,避免無法判斷 in = out 時是 empty 還是 full,必須使用 `in+1` 留一個空格。之後會提到以 locking 的方式使用所有的 Buffer 空間 ![](https://i.imgur.com/ZWby5cc.png) ### Message-Passing System - 讓 Process 之間可以溝通且同步 - IPC 一般來說 OS 會提供兩種操作:Send/Receive 的方式達到同步化,並在背後做各種 memory copy 的處理 - Send(message) - Receive(message) - Message system : Process 不使用 shared variable 達到溝通的目的 - 為了 Process 間的溝通 - 必須建立 communication link - 藉由 Send/Receive 交換資訊 - 實作 communication link 的方式 - physical (e.g. shared memory, HW bus or network) - logical (e.g. logical properties, programmer 在意的事情) - communication 是否有方向性 - 角色是否相對 - Blocking / non-blocking:傳輸行為執行完成才會回傳,或不管對方是否有收到立刻回傳 - send by copy or by reference - 固定大小 / 可變大小 的 message #### Direct communication (如打電話) - Processes 必須要有對方的名稱 - Send(P, message) : 傳輸 message 給 Process P - Receive(Q, message) : 從 Process Q 接收 message - communication link 的特性 - Links 通常為自動建立 - links & processes 為一對一的關係 - link 可以是單向,但通常是雙向 - Direct communication 最大的缺點是關係唯一對一,且連線的對象無法變更,除非重新建立,所以比較難以模組化 (modularity) ### Indirect communication (如寄電子郵件) - Messsages 由 mailboxes(或稱為 port) 導向及接受 - 每一個 mailbox 有自己的 ID - Processes 若共享 mailbox 則可以互相溝通 - Send(A, message):沒有指定接收者,單純將 message 放到 mailbox A - Receive(A, message):沒有指定傳送者,單純將 message 由 mailbox A 接收 - communication link 的特性 - Link 必須由 programmer 建立,透過 Process 間共享 mailbox 來溝通 - 因為沒有指定接收者/傳送者,所以 Link 與 Process 間為 Many-to-Many - Link 可以為單向或雙向 - Mailbox 可以由 Process 或 OS 擁有,通常處理 message 的是另一隻程式 - Mailbox Sharing - 因為可能同時有很多人去讀取 message,但理論上一個 message 應該只能有一個人拿到,有以下幾種解決方法: - Link 只允許兩個 Process (一個 send 及一個 receive,等同 direct,最糟的解法) - 利用 lock 一次只允許一個 Process 拿取 message - 讓 mailbox 自行決定誰來接收。receiver 會先提出要求, mailbox 決定接收者後, sender 會被告知 receiver 是誰,再告知 receiver 來取得 message ### Synchronization - Message passing 可以為 blocking (synchronous)或是 non-blocking (asynchronous) - Blocking send: sender 被 blocked 直到 message 被 receiver 或 mailbox 接收才 return - Nonblocking send: sender 送出 message 之後繼續執行 - Blocking receive: receiver 被 blocked 直到皆收到 message 才 return - Nonblocking receive:若 sender 先 call,則 receiver 正常接收 message ; 若 sender 前 call,則 receiver 只會收到之前的值。所以 function call 通常還會 return 一個 token ,來確定是否真的收到 message - Buffer implementation : non-blocking 通常透過 buffer 實作,只要 buffer 空間沒有滿,就可以一直 send ; 對 receiver 來說就是一直接收,不管 buffer 有沒有東西 - Zero capacity : 通常是 blocking send/receive - Bounded capacity : 若 buffer 滿了, sender 會被 blocked,或是 return 一個 error - Unbounded capacity : 一直送直到系統滿了為止 ## Refernece 1. [清大開放課程 - 作業系統](https://www.youtube.com/watch?v=KjG_BVPJJEs&list=PL9jciz8qz_zyO55qECi2PD3k6lgxluYEV&index=20) 2. [Operating System Concept 9th edition](https://www.os-book.com/OS9/slide-dir/index.html) 3. https://blog.wildsky.cc/posts/os-process-2/