名詞總結
名詞 | 概念 |
---|---|
PCB | 程序控制塊(PCB Process Control Block),系統中存放、管理和控制程序資訊的資料結構稱為 |
PC | 程式計數器 也就是下一條指令的位址 |
PID | 程序ID(Process ID) 程序辨別符 |
TCB | 線程控制塊 |
FCB | 檔案控制塊 |
PSW | 程式狀态字寄存器,用于存放PC、IR等的資訊 |
IR | 指令寄存器,存放到目前進行的指令 |
PID | 系統程序 |
POSIX | 可移植作業系統接口 |
IPC | 程序間的通信機制 |
系統調用 | 指的就是引起核心态和使用者态切換的一種方式 |
半雙工 | 半雙工和全雙工是計算機網絡中的概念,意思是通訊同一時間隻允許一方發送資料(對講機) |
全雙工 | 通信允許兩方向上同時傳輸資料(電話) |
P操作 | 屬于系統調用,來自荷蘭語proveren,即test,檢測,代表wait原語,通常使用P(S)代替wait(S) |
V操作 | 屬于系統調用,來自荷蘭語verhogen,即increment,增加,代表原語signal,通常使用V(S)代替signal(S) |
使用者态 | 一般的作業系統對執行權限進行分級,分别為用保護态和核心态。使用者态相較于核心态有較低的執行權限, 很多操作是不被作業系統允許的,進而保證作業系統和計算機的安全。 |
核心态 | 核心态相當于一個介于硬體與應用之間的層,可以進行硬體的排程、使用,可以執行任何cpu指令,也可以引用任何記憶體位址, 包括外圍裝置, 例如硬碟, 網卡,權限等級最高。 |
使用者态核心态切換 | 三種情況下,使用者态會轉換到核心态,系統調用、程式異常(例如/0,記憶體資源耗盡等)、來自外圍裝置的中斷 |
系統調用/程式接口 | 使用者程式通過系統調用的方式才能對硬體進行使用,或者說作業系統将使用硬體的接口提供給使用者程式 |
中斷 | 中斷是作業系統核心程式奪取cpu的唯一途徑,或者說使用者程式調用核心代碼的唯一途徑,因為在一般情況下,作業系統會将cpu使用權交給應用程式。 |
GDT | 作業系統對應的的段表 |
LDT | 每個程序對應的段表,在PCB中的一個表,LDT放在寄存器 LDTR 中 REGISTER |
TLB | 快表寄存器 |
JVM | Java Virtual Machine Java虛拟機 的縮寫 |
secondary | 緩沖區 |
CHS | 磁盤塊封裝 |
CPU | CPU,Central Processing Unit ,也叫中央處理器 |
李志軍老師網課
P4 作業系統的接口
什麼是作業系統的接口?
系統調用。 作業系統提供了一些重要的函數,這就是作業系統的接口,接口表現為函數調用,有由于是系統提供的,是以稱為系統調用。
什麼是作業系統?
作業系統是執行系統調用的代碼
POSIX ( IEEE制定的一個标準族 )
表頭 | POSIX定義 | 表頭 |
---|---|---|
任務管理 | fork | 建立一個程序 |
execl | 運作一個可執行程式 | |
pthread_create | 建立一個程序 | |
檔案系統 | open | 打開一個檔案或目錄 |
EACCES | 傳回值,表示沒有權限 | |
mode_t_st_mode | 檔案頭部結構:檔案屬性 |
P5 系統調用的實作
CPL (CS) | 目前的特權級 |
RPL (DS) | |
DPL | 目标特權級 |
GDP表 | 存放 CS 與 DS |
IDP表 | 中斷向量表 |
Q1:使用者程式不能随意 jum
使用者程式 調用 放在作業系統記憶體中的東西 時,因為安全性問題,是不能直接通路的,
Q2:分為 核心 / 使用者 态,核心 / 使用者 段
将核心程式和使用者程式隔離,核心态也就是核心态為0,0S服務為 1和2,使用者态為 3
每一條指令執行的時候,都有PC,PC由 CS 和 iP,CS包括的有本段程式處于的特權級資訊,隻有目前特權級大于等于目标特權級,才能執行這條指令,注意數值越小表示特權級越高。
Q3:硬體提供了 主動進入核心的方法
這是使用者程式發起調用核心代碼的唯一方式, int 中斷指令
P6 作業系統的曆史
第一個曆史:計算機的發展
第一階段:批處理 無法實作切換與排程。
第二階段:多道程式交替執行,也就是多程序了,各個作業直接的切換和排程稱為核心,既有 IO 調用,又有計算任務。
第三階段:每個人啟動一個作業,分時系統,各個作業之間快速切換,與前一階段不同的是,定時的來切換,将每個作業占用 OS 的時間相等,核心仍然是任務切換
第四階段:UNIX 出現了
第五階段:Linux 出現了,Linux 由 UNIX 改造而來。
第一個曆史總結:
- 多程序結構是作業系統基本圖譜
- 使用者通過執行程式使用計算機(吻合馮諾依曼的思想)
- 作為管理者,作業系統要讓多個程序合理推進,就是程序管理
- 多程序(使用者)推進時會有記憶體複用等問題。
第二段曆史:作業系統的發展
第二段曆史主要就是 基于檔案的圖像。
DOS就是指令行視窗
通過檔案來使用計算,非常友善,又加上了一些圖形化界面,檔案就是第二個重要的圖像。
第二個曆史,對使用者的使用感覺加倍重視,各種檔案、程式設計環境、圖形界面等
如何通過檔案存儲代碼,執行代碼,操作螢幕
如何讓檔案和操作變成圖示,點選,或者觸碰
任務:
1)掌握、實作作業系統的多程序圖譜,多程序圖像。覆寫兩個部分
- 1、CPU,怎麼從 CPU 出來記憶體。CPU 管理
- 2、記憶體也是一大塊,還講了程序。記憶體管理
2)掌握、實作作業系統的檔案操作視圖,檔案操作圖像。
- 檔案是什麼?其實檔案就是 IO 裝置
- IO 裝置主要講磁盤檔案,IO 怎麼驅動,磁盤怎麼工作,
P7 我們的學習任務
作業系統要管理硬體——CPU管理、記憶體管理,這兩個合起來也就是 程序視圖
作業系統套管理裝置管理——中斷裝置管理、磁盤管理,這兩個合起來就是 檔案視圖
使用者通過接口進入作業系統,程序的管理,就要用 fork,用 fork 管理CPU進行
記憶體是怎麼管理呢?要通過位址,使用記憶體與 多程序圖像是接在一起的
操作裝置為什麼就是操作檔案呢?裝置 對應的是 裝置的檔案,dev, 操作某個檔案,就會操作對應的裝置。
操作檔案,open 一個普通檔案與 open 一個裝置檔案 分别是怎麼展開的
P8 CPU管理的直覺想法
IO 工作的特别慢,一個IO指令執行起來非常慢的
P9 多程序圖像
- 1、操作寄存器如何完成切換:
- 作業系統組織多個程序,用PCB放到不同隊列中,用狀态轉移推進。
- 2、寫排程程式
- DPL和CPL 是用來保護作業系統的一種機制,隻有OS的DPL才等于0,
- 3、程序同步與合作
- 鎖
- 4、位址映射:邏輯記憶體與實體記憶體不同,
- 通過映射表來實作,
- 多程序的位址空間分離,這是記憶體管理的主要内容。
- 程序管理和記憶體管理共同構成了多程序圖像
P10 使用者級線程
1、程序 = 資源 + 指令序列
- 資源 :包括寄存器值,PCB,記憶體映射表
- 線程: 指令序列
- 線程保留了并發和交替執行的優點,同時避免了切換程序的代價
- 實質就是映射表不變,而PC指針改變,展現了分治的思想
2、線程的實用性
- 多線程的使用者互動性好
- 多線程的資源共享
3、總結:使用者級線程切換的核心
- 一個棧變成兩個棧
- 每個線程擁有自己的棧,自己的TCB
- 在切換的時候先切換TCB,在切換棧
- 在建立的時候就是把要切換的PC指針先放到自己的棧中,然後再建立TCB,在将來切回來的時候,首先通過TCB切換到對應的棧中,然後在棧中彈出對應的位址,也就是PC指針。
4、Yield 函數
- 要求能切出去再切回來
- esp
- 線程切換先切TCP,然後再切PC指針,
- 一個線程一個棧
- Yield 切出去的時候,需要先儲存需要下一步執行的位址,也就是下一跳,為了傳回時可以接着往下執行,
- Yield 切換回來的時候,不需要 jum 到下一跳,也就是就是不用切換PC,因為下一跳的位址已經在切出去的時刻壓棧了
5、Create 函數
- 制造出第一次切換時應該的樣子
6、使用者級線程
- 調用Yield函數,自己主動讓出cpu,核心看不見使用者級線程的TCP,核心隻能看見所屬程序而看不見使用者級線程,
- 是以一個使用者級線程需要等待,核心會切到别的程序上,不會切到該程序下的其他使用者級線程!!!
7、核心級線程
- 通路硬體(比如IO網卡等)相關的,一定要用到核心。
- 此時TCP在核心中,核心是可以看到TCP的
- 核心能看見核心級線程,一個線程需要等待,核心會切到所屬程序下的其他核心級線程。
- 核心及線程就叫 Schedule,為了差別與使用者級線程的Yield
P11 核心級線程
1、compare
- 切換程序實際上是切換核心級線程 + 切換資源
- 核 是由作業系統管理的,隻有作業系統才能配置設定硬體資源,使用者級線程不涉及資源的通路
- 一個系統中這三個都有:使用者級線程,核心級線程,程序,這樣才能充分配置設定
2、MMU
- memory management uint 記憶體映射表
3、多處理器 VS 多核
SS stack segment register | 棧段暫存器 |
SP stack pointer | 棧指針 |
ESP extra segment point | 附加段寄存器指針 |
EFLAGS | 你可以當作是儲存目前運作狀态 |
- 隻有多核才能用多線程
- 這裡按老師的意思的話 多核CPU是沒法讓多程序并行執行的… 但是實際上好像并不是這樣,我上SO上搜了一下,發現在多核CPU中,應該每個核都有一個MMU(至少在core i7中是這樣)
- 并行才能最大發揮多核優勢,多程序因為隻有一個mmu的原因不能并發隻能并行,但多線程在隻有一個mmu的情況下也能并行
- 幾個核執行這個記憶體單元裡的程序裡的多線程,再用另外幾個核執行另一個記憶體單元裡的多線程
- 因為多程序MMU不是用的一套
- 通過查閱資料,老師此處說的多程序不能發揮多核價值,或許有誤
- 1.linux下并未對程序線程分别做抽象,都是利用task_struct來描述具體排程的一個單元
- 2.也就是說建立程序、線程的時候其實都是調用的clone
- 3.如果clone傳參共享資源則為建立線程反之則為程序
- 4.是以“多程序在多核上的情況”,其關鍵就在于MMU是否共享
- 5.直接給出回答:MMU通常不是共享的。
- 6.具體參考i7存儲系統框圖,每個core都有一個MMU
- 7.也就是說如果有兩個程序A B,每個程序下有兩個線程A:T1T2 B:T3T4
- 8.兩core單CPU情況下,可以是core1:T1 core2:T3
4、使用者級線程到核心級線程的差別
- 一個棧到一套棧,兩個棧到兩套棧
- 使用者級線程切換是:先TCB切,然後根據TCB再切換使用者棧
- 核心級線程切換是:先TCB切,然後根據TCB再切換一套棧,這一套棧包括使用者棧和核心棧。
5、中斷會自動轉到核心棧
- INT 訪管中斷,對應一個 IRET 剛好是反着的一個過程,彈棧傳回到中斷前的狀态。
- 按下滑鼠,啟動磁盤等硬體中斷
- 時鐘中斷
- IRET :中斷傳回,根據中斷傳回切換到使用者棧
- read 是一個庫函數,調用庫函數會展開成一段 int 指令
- 使用call和ret才能自動壓彈棧,這裡糸統終端就需要手動記錄cs,ip
- 核心棧就是記錄糸統中斷後恢複狀态必須的cs,ip,及使用者棧的資訊
- switch_to 仍然是通過 TCB 找到核心棧指針,然後通過 ret 切到核心棧指針,然後通過 ret切到某個核心程式,最後再用 CS : PC 切到使用者程式
- TCB在核心,從線程1中斷進核心,在核心從TCB1切換到TCB2,然後進線程2使用者态接着執行,是以要先用中斷進入核心,才能進場TCB的切換
P12 核心級線程的實作
- 1、線程1中 從使用者棧到核心棧
- 靠中斷,現在以 系統中斷為例,也就是 fork,fork本身是建立程序系統調用
- 2、線程1中 從核心棧切換到 TCB
- 3、TCB 排程完成從線程1到線程2的切換
- 4、線程2中從 TCB 切到核心棧
- 5、線程2中 從核心棧到使用者棧
P15 schedule 函數 *
count 保證了響應時間的上界為 2p p為初始值
經過 IO 之後,count就會變大, IO 師姐越長,counter 越大,照顧了IO程序,也就是照顧了前台程序
背景程序一直按照counter輪轉,近似了SJF
每個程序隻用維護一個 counter 變量,簡單高效
COUNT的複用,既作為優先級,又作為時間片,count會改變,優先級是動态的
首先是找到所有就緒态任務的最大counter,大于零則切過去,否則更新所有任務的counter,即右移一位再加priority
然後進入下一次的找最大counter大于零則切否則更新counter,
是以說那些沒在就緒态的counter就一直在更新,數學證明出等的時間越長counter越大
等他們變成就緒态了,由于counter大,也就可以優先切過去了
P16 程序同步與信号量
程式和程序關系:
一個程序代表程式的一次執行,程式可以多次執行,也就對應了多個程序
等待是程序同步的核心,需要讓程序 走走停停 來保證多程序合作的合理有序
等信号量期間是阻塞的
請求的信号量的時候會把自己阻塞起來,直到擷取到信号後再激活變成就緒狀态
信号不能滿足要求,因為信号隻是有或者沒有,是以要引入信号量
信号量就是用來記錄一些資訊量,并根據這個資訊來總結是 sleep還是 weakup,其實就是一個整形變量
信号隻有兩種狀态,适用于單程序
信号量可以涵蓋更多地資訊,适用于多程序
信号量的 P操作和 V操作
信号量是一個結構體
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-6VTKCWT4-1622192224112)(C:\Users\lh\AppData\Roaming\Typora\typora-user-images\image-20210526142514074.png)]
P17 信号量臨界區保護
驗證保護算法是否合理的标準:
- 互斥進入
- 有空讓進
- 有限等待
進入臨界區的保護方法
- 1、軟體方法
- 1)輪換法 有空讓進效果不好!!!
- 2)标記法 可能會造成無限制空轉等待
- 3)非對稱标記 結合了标記和輪轉兩種思想
- 兩個程序:Peterson算法
- 多個程序:面包店算法
- 2、 硬體方法
- 關閉中斷來關閉排程即可
- 但是注意,多CPU的時候不好使。這裡涉及到多cpu如何schedule
- 3、 硬體原子指令
-
其實是用 mutex鎖信号量 來保護信号量,為了解決mutex仍然需要保護的問題
使用硬體級原子操作,不能被打斷不能切出去進行排程
-
應用:
- 單核系統開關中斷
- 多核系統原子變量自旋鎖。
總結:
- 硬體原子指令法,不須換保護變量,
- 軟體的鎖,需要設定一個保護變量,會出現無休止的套娃。
P18 信号量的代碼實作 *
P19 死鎖處理
死鎖即是形成了資源的等待環路,死鎖的4個必要條件
- 1、互斥使用
- 2、不可搶占
- 3、請求和保持
- 4、循環等待
死鎖處理方法:
- 1、死鎖預防:破壞死鎖出現的條件
- 1.1 在程序執行之前,一次性申請所有需要的資源,不會占用資源再去申請其他資源
- 1.2 對資源類型進行排序,自願申請必須按順序進行,不會出現環路等待。
- 總結:引入太多不合理因素
- 2、死鎖避免:當請求出現時,先假裝配置設定,然後用銀行家算法,也就是在執行前檢測每個資源的請求,如果會造成死鎖就拒絕
- 2.1 銀行家算法,缺點是複雜度太高,效率低
- 總結:每次申請都執行銀行家算法 O(mn),效率太低
- 3、死鎖檢測+恢複
-
等出現問題了,有一些程序因為死鎖而停住了,再處理,選擇一個程序進行復原,然後再用銀行家算法來算是否能找到安全序列,如果不行,再復原,直到所有程式都能執行。
但是復原是個大問題!!!已經寫入磁盤,還得退回來,那就很麻煩了。
- 恢複很不容易,進城造成的改變很難恢複
-
- 4、死鎖忽略
- 也就是重新開機
- windows,linux個人版 都不做死鎖處理,直接忽略,大不了重新開機就好了,小機率事件,代價可以接受
- 死鎖出現是不确定的低機率事件
P20 記憶體的使用與分段
一段記憶體,一段程式,這個程式被分為多個段,有代碼段,變量段等,每個段在記憶體中找到一塊空閑區域,每個段将找到位址的初始值記錄在對應段的LDT中,然後将LDT表放在PCB中,又因為編譯、連結後的裝入子產品的位址都是從0開始的,即可執行檔案指令位址不變,也就是PC指針的初始值都是從0位址開始取值執行,在每次取址的時候都會查PCB中的LDT表,根據LDT表中對應某個段的基址來找對應的實體位址,也就是從程式中的邏輯位址找到對應在記憶體中的實體位址,然後進行相應的操作。
段可以有:
主程式段、變量集段、函數庫段、動态數組(堆)段、棧段
通過 段号+段内偏移 進行取址
不是将整個程式,而是将各個段分别放入記憶體中,每個段都需要記錄其基位址,存在一個表中,該表稱為段表,段表儲存到PCB中
每個程序對應一個PCB,PCB中有一個與之對應的 LDT段表,某個程序在運作時,會首先把自己的LDT表在寄存器 ldtr (register) 中更新,這個寄存器暫且了解成隻有一個,是以每次取址時都是與 ldtr寄存器 中的基址進行相加的運算,是以當需要切換到另外一個程序時,ldtr寄存器也會跟着切換,變成另外一個程序的 LDT段表。
與之前講過的位址映射表聯想起來,這個LDT段表 就是 位址映射表
P21 記憶體的分區與分頁
三步:
- 第一步:分段 (LDT段表),将一個程式分成多個段落,編譯幹的事兒
- 第二步:找到一段空閑分區,需要再記憶體中劃分空閑區
- 第三步:通過一個表,将映射關系做好,需要通過磁盤讀寫,把程式載入進來,這是裝置驅動的事兒,
- 這三步完成後就建立了一張映射表,和PCB關聯在一起,這是前面講的程序管理的事情。
這三步完成以後,在以後的運作過程中,就可以通過運作時重定位取址執行,程式執行起來,記憶體也跟着使用起來了。
實體記憶體需要分頁
程式、使用者是需要分段
32位作業系統,也就是有32位位址總線,32位位址總線可以有 2^32,也就是4G的記憶體空間,
就需要對這4G的記憶體空間來建立一個虛拟頁到實體頁的映射轉換,
4G的記憶體空間,沒一頁是 4kB,那麼就有 1M ( 也就是2^20 ) 的頁,這個映射表就是這 1M 個頁的映射關系
頁表的存儲也是有一個寄存器,叫 C23 寄存器,這個與段表非常類似,也是存在PCB中的。
通過頁來找實體位址這件事,是通過硬體做的,CPU都有一套叫 MMU 的記憶體管理單元,裡面有一套管理分頁的電路
隻要你把頁表的起始位址給 C23 寄存器,寄存器就是硬體,MMU 就可以根據偏移位址等找出對應的實體位址,
一個程式是由多個段組成的,為了避免記憶體碎片帶來的浪費,這每個段不能直接放在記憶體中,而是要先把記憶體分頁,把這個段打散成多個頁來放在記憶體中
MMU memory manager unit 記憶體管理單元
P22 多級頁表與快表
一個常識:CPU在執行指令的時候,如果是做一些加減乘除類似的運算,那些都是在CPU内部做的,其速度是非常快的,CPU執行指令主要花費的時間不是在運算上,而是花費在通過位址總線來通路記憶體,這個速度是很慢的,也就是取址是慢的,
問題:
- 需要頁表項 連續
- 也需要降低也變的存儲空間
方法一:隻存放用到的頁
- 缺點:頁表編号不連續
方法二:多級頁表
- 相當于書的目錄的作用。既減輕了存儲壓力,每個還都連續,空間效率比較高,但是浪費了時間
方法三:多級頁表 + 快表
- 快表相當于一個cache,把頻繁使用的位址映射記錄下來
- TLB 是一組相連快速存儲,是寄存器
- 在時間可空間上做到最優化。
目錄表項和頁号表項都是2^10個
offset是一共有2^12個麼,每個offset的大小是4KB麼?這塊沒了解,求解答
頁面的大小是有offset所占位數決定,而2的12次方等于4KB
P23 段頁結合的實際記憶體管理
程式分段
- 配置設定端、建段表 LDT,段不能分開,是需要合在一起的。
實體記憶體分頁
- 配置設定頁、建頁表
基位址在PCB中,要把程式放入記憶體,才能開始使用記憶體
隻要做好段表和頁表,執行指令時MMU就能自動完成,MMU是用來計算邏輯位址到虛拟位址再到實體位址的轉換的,這個過程是由硬體來完成,移位的操作很快的。是以需要先把段表和頁表做好。
頁段同時存在是重定位
邏輯位址 | 虛拟記憶體 | 虛拟位址 | 實體位址 |
---|---|---|---|
cs : ip 段号 : 段内偏移 |
根據段表,看段号找到基址,再根據偏移,産生出的位址就是虛拟記憶體的虛拟位址
這個虛拟位址不是真的位址,需要再次經過一個映射,這次的映射支援分頁機制,這次根據頁号和偏移找到對應的實體位址,
1)子程序的資料段和代碼段映射到不同的虛拟記憶體位址,每個程序配置設定 64M 虛拟記憶體位址
2)父程序和子程序共用一套頁目錄表,因為虛拟位址不同,頁目錄号号不同,不打架
3)在頁目錄表中增加對應頁框号表,即父程序和子程序中對應的虛拟位址不同,但是不同位址映射到了同一塊頁框,也即映射到同一塊實體記憶體。
4)然後對子程序設定共享記憶體段屬性為隻讀,這樣在子程序往裡寫的時候,會發現隻讀,會修改映射,映射到其他空間!!!
達到對于使用者來講雖然是操作的同一個位址,但其實對應的是實體記憶體的兩塊區域,即子程序和父程序的記憶體區域是分隔的!!!
P24 記憶體換入-請求調頁 swap in
段頁同時存在,就需要用到虛拟記憶體
上層使用者是看不到實體位址的,他們看到的就是0-4G的一個空間,(這個是在32位作業系統上虛拟記憶體的大小)
每個程序可以單獨使用這4G記憶體,就像是單獨擁有這4G記憶體一樣,作業系統就是給使用者提供了這樣一個假象,好像使用者可以在0-4G的記憶體上随意使用這個記憶體
後面的從虛拟記憶體到實體位址的映射,使用者是全然不知的,作業系統是實作了從虛拟記憶體到實體記憶體的映射
實體記憶體一般是比較小的,有1G,有2G,但是在使用者看來都是4G,
使用者執行的程式都在磁盤上,需要将磁盤上的指令放在記憶體上,才能完成執行指令
所有指令都是一句一句執行的,是以當執行完一句後,再次換入換出到記憶體上,這樣就實作了大的虛拟記憶體映射到了小的實體記憶體上。
請求的時候才從虛拟記憶體到實體記憶體映射,才換入到實體記憶體
虛拟記憶體相當于一個大倉庫,
P25 記憶體換出
通路位址發現缺頁,産生缺頁中斷,從磁盤中讀取,換入
當從磁盤讀入時,發現實體記憶體不足,也就是頁框不足,就要用 clock 算法産生時鐘中斷,淘汰掉一個頁面,寫進磁盤
這個過程就是 swap in 和swap out 的swap分區管理
這樣通過 記憶體,時鐘中斷,缺頁中斷,磁盤,磁盤管理,磁盤驅動,這樣就形成了swap換入換出的一個樣子,
而實作換入換出,是為了實作虛拟記憶體,這個就是實作虛拟記憶體的核心
實作虛拟記憶體,是為了實作段頁
實作段頁,是為了實作作業系統管理記憶體的思想
管理記憶體,是為了實作讓程式能夠載入記憶體,也就是讓程式能夠執行起來
讓程式能夠執行起來,這就是程序
記憶體管理和程序管理這兩個部分是作業系統的核心,
在加上一些裝置驅動,檔案系統,系統初始化,系統引導,這些加起來就是一套完整的作業系統
P26 IO與顯示器
一台計算機,有CPU,有記憶體,有顯示器,有鍵盤,即使在沒有磁盤的情況下,也就可以開始使用了,
I/O就是輸入輸出,I/O裝置就是可以将資料輸入到計算機或将計算機資料輸出的裝置,常見的:滑鼠、鍵盤、音響、顯示器、列印機、話筒、攝像頭等等。
**I/O控制器:**CPU無法直接控制I/O裝置,需要一個電子部件去充當中間人,這個部件就是I/O控制器,CPU控制I/O控制器,I/O控制器控制I/O裝置。
假如我們的CPU能夠控制I/O裝置,那不同的廠商、不同型号的裝置,都要對應進行編碼,顯然是不切實際的,是以CPU要采用通用排程方式排程I/O裝置進而需要I/O控制器。
外設的控制器:
顯示器的 I/O 控制器:對應顯示卡
鍵盤:輸入 對應
磁盤:讀寫
核心是就三個:
- 1、CPU向外設發出一條 讀或寫 的指令,也就是
- 2、外設工作完成的時候,向CPU發出中斷
- 3、CPU進行中斷
但是OS為了統一,要想讓外設實作驅動需要做三件事:
- 1、向外設的核心控制器的某些寄存器端口或者是某些存儲端口,發出讀寫指令,是以第一個部分就是 通過 out 向外設發出指令,這個是計算機/CPU使用外設最核心的東西
-
2、但是要想寫出上面的幾條核心指令,必須要對硬體非常了解,要知道硬體對應的端口,硬體指令的格式等等,這些細節非常麻煩,因為不一樣的外設制造廠商通常造出的裝置也不一樣,作業系統為了隐蔽這些細節,就做了一個統一的視圖,也就是将所有的外設都做成檔案,根據檔案所對應的檔案名,根據檔案描述的結構中的資訊,決定了走那條路,最終到達某個裝置對應的 out 代碼,
是以第二個部分就是把不同裝置對應的 out 代碼,采用檔案的方式,向上封裝起來,
- 3、進行中斷處理
- 1、CPU 通過 out 指令向 外設 發出指令
- 2、通過檔案形成統一的檔案視圖
- 3、進行中斷處理
對于顯示器來說:
從CPU開始out,也就是從使用者指令開始,
P27 鍵盤
按下鍵盤就相當于中斷,
對于鍵盤來說:
從鍵盤按下開始講故事,
将鍵盤鍵入的字元 放入 緩沖隊列
裝置驅動的核心内容:
無非就是 out 、read 等這樣的指令
要麼是CPU 發出指令,要麼是裝置發出中斷,
無非是最終和檔案接在一起
其他的内容就是一些包裝。
鍵盤的回顯,和顯示器顯示一樣
鍵盤将鍵入的字元放入緩沖區,顯示器從緩沖區中讀取
一個是 write_q, 顯示器
一個read_q,鍵盤
P28 生磁盤的使用
怎麼讓磁盤驅動起來,也就是用起來
CPU中的磁盤控制器通過out寫一些指令,磁盤收到指令後進行讀或者寫
磁盤工作完成之後,向CPU發出中斷,做一些後續處理
part1:
三步:
移動磁頭到相應的磁道上
旋轉磁盤到相應的扇區上
最後與記憶體進行相應的讀(磁生電)或者寫(電生磁)
磁盤的IO過程:控制器 尋道 旋轉 傳輸
控制器中要包含幾個資訊
柱面、磁頭、扇區、緩存位置
out指令中要指定上面幾個資訊的具體數值,然後将 out 指令發出去
作業系統為了将整個磁盤抽象起來,把上面的幾個資訊整合封裝起來,用唯一的表示 也就是盤塊号 來辨別,
這樣就可以隻需要知道 block号,作業系統就可以自己通過這個 block号 找到具體的位置
這就是使用作業系統的系統,可以将使用硬體變得簡單且高效
應用程式通過盤塊号來通路磁盤,效率得到了很大的提升
作業系統在使用抽象的時候,也要想辦法将使用的過程變得高效,磁盤的尋道時間是相對來說很慢的,尋道時間也就是移動磁頭的時間,而其他的啟動時間、傳輸時間都很迅速,不是最主要的時間消耗。
因為相鄰盤塊通過是連續使用的,為了減少尋道時間,就把相鄰盤塊放在同一磁道上。
part2 四個抽象
第一個抽象
- CHS 磁盤塊封裝
- 就是抽象出 block, chs 抽象為盤塊 block
第二個抽象 核心就是多個磁盤通路請求出現在請求隊列中時該怎麼辦? 其實就是排程問題
- 也就是 把 block 放入請求隊列時産生了沖突該怎麼辦,也就是磁盤排程算法,實際中通常使用電梯算法
第三個抽象
- block的集合抽象為檔案,根據 FCB 找到 inode ,根據 inode 再找到對應的 block
第四個抽象
- 檔案的組織形式抽象為目錄,根據給出的路徑 找到 FCB
給我一個路徑名,這個路徑名就是一個樹狀結構,我能夠得到這個檔案的 FCB
根據這個 FCB ,我能得到 inode
根據 inode 和對應的映射,就能找到盤塊号
根據盤塊就能放到電梯隊列上,
根據電梯隊列,就能在磁盤中斷的時候把對應的 盤塊 讀出來,算出 CHS,并把 CHS 發給控制器
控制器根據 CHS 就可以驅動馬達,控制磁盤讀寫相應的盤塊
最終就是有了路徑,就找到了磁盤的某個盤塊 的映射。
磁盤排程算法
1、先來先服務 FCFS, FCFS-First Come First Serve
根據程序請求房屋内磁盤的現後順序進行排程。符合慣性思維,但在很多時候,效果很差。
2、最短尋找時間優先 SSTF,SSTF-Shortest Seek Time First
學過資料結構與算法的話,核心思想就是貪心算法,該算法會優先處理與目前磁頭最近的磁道的需求。
3、掃描算法 SCAN
核心思想,隻有磁頭移動到最外側磁道的時候才能往内側移動,移動到最内側的時候才能向外側移動。
4、電梯算法 C-SCAN
總結
1、程序得到 盤塊号,算出扇區号,這裡埋下一個檔案管理的伏筆
2、通過扇區号,得到緩沖記憶體,使用電梯算法,把緩沖記憶體放到請求隊列中,
3、接下來的工作就是硬體幹的,就不用占用CPU了,程序就可以 sleep_on 了
4、然後磁盤工作完成後,産生中斷,将程序喚醒 weak_up
P29 從生磁盤到檔案
實際上我們使用生磁盤,并不是直接通過盤塊号,而是通過檔案,也就是字元流,檔案就是由字元流來辨別的
本章節就是講,從盤塊号怎麼抽象出 檔案,反過來怎麼從檔案找到盤塊号進行使用,進行映射的抽象。作業系統封裝了這個映射,并進行維護。
盤塊是邏輯的,實際上讀取的是扇區,其讀取效率交由下層解決,即電梯算法
引入檔案後,那就不叫生磁盤了,那就是 cook_disk ,也就是熟磁盤 ,哈哈哈哈好有趣
FCB 記錄起始塊,檔案控制塊
映射有很多種:
順序存儲:類似于數組
鍊式存儲:類似于連結清單
索引結構:inode ( i 對應的就是 index , node 就是相當于節點,一個結構體嘛,比如 FCB 就是一個結構體,通過結構體來查詢,是以叫他 inode)
索引就是檔案分成不同的實體塊存入磁盤,對每個實體塊都有一個索引與之對應,需要讀寫時就通過索引表查詢其實體位址進行相關操作。
總結:
從檔案找到盤塊号,怎麼找呢?通過 檔案控制塊TCB的映射關系,再加上一些小小的計算
P30 檔案使用磁盤的實作 *
根據檔案名找到 inode·,這個檔案名不是但指檔案的名字,還包括整個路徑,是以是根據 路徑名找到 inode
根據 inode 找到盤塊号
根據盤塊号往電梯隊列中放,
根據電梯隊列中的盤塊号,算出 chs cfs
最後把 是 out 發在磁盤控制器中
最後磁盤控制器驅動馬達,電生磁、磁生電,對磁盤産生讀或寫
P31 目錄與檔案系統
整個磁盤變成一棵 目錄樹
chs 抽象為盤塊 block,block的集合抽象為檔案,檔案的組織形式抽象為目錄
第四層抽象:整個磁盤被抽象為一個檔案系統
給我一個路徑名,這個路徑名就是一個樹狀結構,我能夠得到這個檔案的 FCB
根據這個 FCB ,我能得到 inode
根據 inode 和對應的映射,就能找到盤塊号
根據盤塊就能放到電梯隊列上,
根據電梯隊列,就能在磁盤中斷的時候把對應的 盤塊 讀出來,算出 CHS,并把 CHS 發給控制器
控制器根據 CHS 就可以驅動馬達,控制磁盤讀寫相應的盤塊
最終就是有了路徑,就找到了磁盤的某個盤塊 的映射。
P32 目錄解析代碼的實作 *
作業系統的全圖:
作業系統是一個什麼東西呢?
是一個管理硬體的軟體,硬體比如 CPU、記憶體,外設等
OS 首先是管理 CPU,這就引入了OS 第一個重要的視圖——多程序圖像
在程式執行的過程中,為了讓程式執行,需要從記憶體中不斷地取址執行取址執行,這就需要把記憶體使用起來
記憶體就引入了 分段分頁,段頁合作,虛拟記憶體,還有記憶體的換入換出,這樣就可以把程式放進記憶體中的某個位置,将指令運作起來,記憶體也使用起來了,
在程式執行時,對于一些 open,read 等檔案指令,就是根據檔案視圖與外設 如磁盤、顯示器、鍵盤等也聯系起來了,将各種裝置就業使用起來了
OS 的視圖有兩大視圖
多程序視圖是核心,多個程序轉來轉去,實作了 CPU、記憶體的運轉,
然後再加上 檔案的open、read等接口,就通過 IO 把各個外設也使用起來了,
多程序視圖往往又是和 IO 、記憶體等并行的往前推進
第二大視圖是 檔案視圖,用來通路 IO 端口,
将兩大視圖,再加上系統接口,系統啟動,這個系統就能自己從磁盤上載入進來,打出 logol,然後在記憶體中展開,建立多個程序
使用者敲指令來啟動程序,使用者就把 PPT,word、MP3 、背景編譯程式 等應用程式工作起來,計算機就解決了各種有待解決的各種問題
完結撒花~
實驗沒有做,還是很空的。
leetbook 硬核作業系統指南
程序的系統調用
下面是 UNIX 作業系統和 Windows 作業系統系統調用的對比
UNIX | Win32 | 說明 |
---|---|---|
fork | CreateProcess | 建立一個新程序 |
waitpid | WaitForSingleObject | 等待一個程序退出 |
exit | ExitProcess | 終止執行 |
open | CreateFile | 建立一個檔案或打開一個已有的檔案 |
close | CloseHandle | 關閉檔案 |
線程的系統調用
調用函數 | 功能 |
---|---|
thread_create | 建立新的線程 |
thread_exit | 退出線程 |
thread_join | 表示一個線程可以等待另一個線程退出 |
thread_yiel | 表示允許線程自動放棄 CPU 進而讓另一個線程運作 |
為了使編寫可移植線程程式,IEEE 在 IEEE 标準 1003.1c 中定義了線程标準。線程包被定義為
Pthreads
POSIX線程(通常稱為pthreads)是一種獨立于語言而存在的執行模型,以及并行執行模型
每個工作流程都稱為一個線程,可以通過調用POSIX Threads API來實作對這些流程的建立和控制。可以把它了解為線程的标準。
POSIX Threads 的實作在許多類似且符合POSIX的作業系統上可用,例如 FreeBSD、NetBSD、OpenBSD、Linux、macOS、Android、Solaris,它在現有 Windows API 之上實作了pthread。
線程調用 | 描述 |
---|---|
pthread_create | 建立一個新線程 |
pthread_exit | 結束調用的線程 |
pthread_join | 等待一個特定的線程退出 |
pthread_yield | 釋放 CPU 來運作另外一個線程 |
pthread_attr_init | 建立并初始化一個線程的屬性結構 |
pthread_attr_destory | 删除一個線程的屬性結構 |