作業系統學習筆記(一)
Updated December 25, 2018
作業系統引論
多道程式設計的基本概念
在多道批處理系統中, 使用者所提交的作業先存放在外存上, 並且排成一個佇列, 稱為後備佇列, 由作業排程程式按一定的演算法, 從後備佇列中選擇若干個作業調入記憶體, 使它們共享CPU和系統中的各種資源. 由於同時在記憶體中裝有若干道程式, 可以利用程式在I/O操作時的CPU空擋時間, 使多道程式交替地執行, 這樣便可以保持CPU處於忙碌狀態.
多道批處理系統的優缺點
- 資源利用率高: CPU可以保持忙碌狀態, 可提高記憶體的利用率, 可提高I/O裝置的利用率
- 系統吞吐量大: CPU和其它資源保持忙碌狀態, 作業僅當完成或執行不下去時才進行切換, 系統開銷小
- 平均週轉時間長: 由於作業要排隊依次進行處理, 因而作業的週轉時間較長
- 無互動能力: 使用者一旦把作業提交給系統, 直至作業完成, 使用者都不能與自己的作業進行互動
作業系統的基本特性
- 併發: 指兩個或多個事件在同一時間間隔內發生. 這些事件巨集觀上是同時發生的, 但是微觀上是交替發生的. 一個單核處理機同一時刻只能執行一個程式, 因此作業系統會負責協調多個程式交替執行
- 共享: 是指系統中的資源可供記憶體中多個併發執行的程序共同使用
- 互斥共享方式: 系統中的某些資源, 雖然可以提供給多個程序使用, 但一個時間段內只允許一個程序訪問該資源
- 同時共享方式: 系統中的某些資源, 允許同一個時間段內由多個程序對它們進行訪問
- 虛擬: 通過某種技術將一個物理實體變為若干個邏輯上的對應物
- 時分複用技術
- 空分複用技術
- 非同步: 在多道程式環境下, 允許多個程式併發執行, 但由於資源有限, 程序的執行不是一貫到底的, 而是走走停停, 以不可預知的速度向前推進, 這就是程序的非同步性
系統呼叫
應用程式通過系統呼叫請求作業系統的服務.
系統呼叫是作業系統提供給應用程式(開發人員)使用的介面, 可以理解為一種可供應用程式呼叫的特殊函式
應用程式 | 可直接進行系統呼叫, 也可使用庫函式. 有的庫函式涉及系統呼叫, 有的不涉及 |
---|---|
程式語言 | 向上提供庫函式. 有時會將系統呼叫封裝成庫函式, 隱藏系統呼叫的一些細節, 使上層進行系統呼叫更加方便 |
作業系統 | 向上提供系統呼叫 |
裸機 |
系統呼叫的過程
- 傳遞系統呼叫引數
- 執行陷入指令(使用者態)
- 執行系統呼叫相應服務程式(核心態)
- 返回使用者程式
注意: 陷入指令是在使用者態執行的, 執行陷入指令之後立即引發一個內中斷, 從而CPU進入核心態. 發出系統呼叫請求是在使用者態, 而對系統呼叫的相應處理在核心態下進行
中斷和異常
發生中斷就意味著需要作業系統介入, 開展管理工作. 當中斷髮生後, CPU立即進入核心態, 當前執行的程序暫停執行, 並由作業系統核心對中斷進行處理
中斷的分類
- 內中斷(異常): 訊號的來源是CPU內部, 與當前執行的指令有關
- 自願中斷–指令中斷
- 強迫中斷(如硬體故障(缺頁), 整數除以0)
- 外中斷: 訊號來源是CPU外部, 與當前執行的指令無關
- 外設請求(I/O操作完成發出的中斷訊號)
- 人工干預
程序
程序實體: 由程式段, 資料段, PCB三部分構成
程序: 程序實體的執行過程, 是系統進行資源分配和排程的一個獨立單位
建立撤銷程序, 實質上是建立撤銷程序實體中的PCB
PCB(記錄型資料結構)
作為獨立執行基本單位的標誌. 能實現間斷性執行方式, 系統可將CPU現場資訊儲存在被中斷程序的PCB中, 供該程序再次被排程執行時恢復CPU現場時使用
- 程序描述資訊: 程序識別符號PID和使用者識別符號UID
- 程序控制和管理資訊: 程序的當前狀態, 程序優先順序
- 處理機狀態: 處理機的各種暫存器的內容
- 資源清單: 鍵盤, 滑鼠等
PCB的組織方式
在一個系統中, 通常有數十數百乃至更多的PCB, 為了能對它們加以有效的管理, 應該用適當的方式把這些PCB組織起來
- 線性方式: 將系統中所有的PCB都組織在一張線性表中, 將該表的首址存放在記憶體的一個專用區域中
- 連結方式: 把具有相同狀態程序的PCB分別通過PCB中的連結字連結成一個佇列. 可以形成就緒佇列, 若干個阻塞佇列和空白佇列
- 索引方式: 系統根據所有程序狀態的不同, 建立幾張索引表, 如就緒索引表, 阻塞索引表, 並把各索引表在記憶體的首地址記錄在記憶體的專用單元中
程序的狀態
- 就緒態: 已經具備執行條件, 但是由於沒有空閒CPU, 暫時不能執行
- 執行態: 程序已經佔有CPU, 並在CPU上執行
- 阻塞態: 指正在執行的程序由於發生某事件暫時無法執行時的狀態
- 建立態: 由程序申請一個空白PCB, 並向PCB中填寫用於控制程序的資訊
- 終止態: 將PCB清零, 並將PCB返還系統
程序同步
程序同步是對多個相關程序在執行次序上進行協調, 使併發執行的諸程序之間能按照一定的規則共享系統資源.
為了實現對臨界資源的互斥訪問, 需遵循以下原則:
- 空閒讓進: 當無程序處於臨界區時, 應允許一個請求進入臨界區的程序立即進入臨界區
- 忙則等待: 當已有程序進入臨界區時, 其它試圖進入臨界區的程序必須等待
- 有限等待: 對請求訪問臨界資源的程序, 應保證在有限時間內進入臨界區(保證不會飢餓)
- 讓權等待: 當程序不能進入臨界區時, 應立即釋放處理機, 以免程序陷入忙等狀態
硬體方法實現程序互斥:
- 關中斷
- Test and Set指令
- Swap指令
訊號量機制
可以用一個訊號量表示系統中某種資源的數量, 使用者程序可以通過使用作業系統提供的一對原語來對訊號量進行操作.
- 整型訊號量
int s = 1;
void wait(int s){
while(s <= 0);
s = s-1;
}
void signal(int s){
s = s+1;
}
- 記錄型訊號量
//記錄型訊號量的定義
typedef struct{
int value; // 剩餘資源數
struct process *L; // 等待佇列
}semaphore;
void wait(semaphore *s){
s->value--;
if(s->value < 0)block(s->list);
}
void signal(semaphore *s){
s->value++;
if(s->value <= 0)wakeup(s->list);
}
- 生產者消費者問題
int in = 0, out = 0; item buffer[n];
semaphore mutex = 1, empty = n, full = 0;
void producer(){
do{
producer an item nextp;
wait(empty); wait(mutex);
buffer[in] = nextp;
in = (in + 1) % n;
signal(mutex); signal(full);
}while(True);
}
void consumer(){
do{
wait(full); wait(mutex);
nextc = buffer[out];
out = (out + 1) % n;
signal(mutex); signal(empty);
consumer the item in nextc;
}while(True);
}
- 哲學家進餐問題
semaphore chopstick[5] = {1, 1, 1, 1, 1};
semaphore mutex = 1; //互斥地取筷子
Pi(){ //i號哲學家的程序
while(1){
P(mutex); P(chopstick[i]); //拿左
P(chopstick[(i+1)%5]); //拿右
V(mutex);
吃飯
V(chopstick[i]);
V(chopstick[(i+1)%5]);
思考
}
}
程序通訊
指程序之間的資訊交換
高階通訊機制:
- 共享儲存器系統: 相互通訊的程序共享某些資料結構或共享儲存區
- 管道通訊系統: 管道, 是指用於連線一個讀程序和一個寫程序以實現它們之間通訊的一個共享檔案, 又叫pipe檔案. 寫程序以字元流形式將大量的資料送入管道, 讀程序則從管道中接收資料.
- 訊息傳遞系統: 不必藉助任何共享儲存區或資料結構, 而是以格式化的訊息為單位, 將通訊的資料封裝在訊息中, 並利用作業系統提供的一組通訊命令原語, 在程序間進行訊息傳遞
- 客戶機-伺服器系統
執行緒
引入程序的目的是為了使多個程式能併發執行, 以提高資源利用率和系統吞吐量.
引入執行緒的目的是為了減少程式在併發執行時所付出的時空開銷.
執行緒是一個基本的CPU執行單元, 也是程式執行流的最小單位
執行緒是排程的基本單位
由於程序是一個資源的擁有者, 因而在建立, 撤銷和切換中, 系統必須為之付出較大的時空開銷. 執行緒間併發, 如果是同一程序內的執行緒切換, 則不需要切換程序環境, 系統開銷小
處理機排程與死鎖
排程的實質是一種資源分配, 處理機排程是對處理機資源進行分配.
飢餓: 某程序/作業長期得不到服務
- 作業排程(高階排程):
根據某種演算法, 從外存上處於後備佇列的作業中挑選一個或多個作業, 給它們分配記憶體等資源, 建立相應的程序(建立PCB). - 記憶體排程(中級排程):
引入中級排程的目的是提高記憶體利用率和系統吞吐量
中級記憶體實際上就是儲存器管理中的對換功能
把那些暫時不能執行的程序調至外存等待, 此時程序的狀態稱為掛起狀態, 當它們已具備執行條件且記憶體又稍有空閒時, 由中級排程決定重新調入記憶體. - 程序排程(低階排程):
按照某種演算法, 從就緒佇列中選擇一個程序為其分配處理機
程序切換是指一個程序讓出處理機, 另一個程序佔有處理機的過程, 對原來執行的程序儲存各種資料, 對新的程序恢復各種資料
處理機的利用率
CPU的利用率=CPU有效工作時間/(CPU有效工作時間+CPU空閒等待時間)
排程演算法
- 先來先服務(first-come first-served)排程演算法
該演算法可用於作業排程和程序排程, 系統按照作業到達的先後次序來進行排程, 優先考慮在系統中等待時間最長的作業 - 短作業優先(short job first)排程演算法
該演算法以作業/程序的長短來計算優先順序, 作業/程序越短, 優先順序越高.
對短作業有利, 長作業不利, 還可能造成飢餓. - 優先順序排程演算法(priority-scheduling algorithm)
在優先順序排程演算法中, 基於作業的緊迫程度, 由外部賦予作業相應的優先順序, 排程演算法根據該優先順序進行排程. - 高響應比優先排程演算法(Highest Response Ratio Next)
為每個作業引入一個動態優先順序, 即令優先順序隨等待時間延長而增加, 避免了長作業飢餓的問題. 該優先順序的變化規律可描述為: 優先權=(等待時間+要求服務時間)/要求服務時間 - 基於時間片的輪轉(round robin)排程演算法
系統根據FCFS策略, 將所有的就緒程序排成一個就緒佇列, 並設定每隔一定時間間隔(如30ms)產生一次中斷, 啟用系統中的程序排程程式, 如果程序尚未執行完畢, 排程程式把它送往就緒佇列的末尾, 將CPU分配給隊首程序. - 多佇列排程演算法
該演算法將系統中的程序就緒佇列從一個拆分為若干個, 將不同型別或性質的程序固定分配在不同的就緒佇列, 不同的就緒佇列採用不同的排程演算法 - 多級反饋佇列(multileved feedback queue)排程演算法
- 在系統中設定多個就緒佇列, 併為每個佇列賦予不同的優先順序. 第一佇列優先順序最高, 第二個次之. 該演算法為不同佇列中的程序所賦予的執行時間片的大小也不相同, 在優先順序越高的佇列中, 其時間片越小.
- 新程序進入記憶體後, 先將其放入第一佇列的末尾, 每個佇列都採用FCFS演算法, 當輪到該程序執行時, 若用完時間片程序還未結束, 則將該程序放入下一級佇列隊尾
- 只有第k級佇列為空時, 才會為第k+1級隊頭的程序分配時間片
死鎖
在併發環境下, 各程序因競爭資源而造成的一種互相等待對方手裡的資源, 導致各程序都阻塞, 都無法向前推進的現象
- 產生死鎖的必要條件
互斥條件, 請求和保持條件, 不可搶佔條件, 迴圈等待條件 - 處理策略
預防死鎖: 破壞產生死鎖的四個必要條件
避免死鎖: 銀行家演算法
死鎖的檢測與解除