天天看點

作業系統學習筆記名詞總結李志軍老師網課leetbook 硬核作業系統指南

名詞總結

名詞 概念
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 删除一個線程的屬性結構

繼續閱讀