操做系統學習筆記

BIOS

存在內存的特定地址,啓動執行,檢查計算機硬件java

加載位於硬盤特定地址的BootLoader,管理權交給BootLoadernode

BootLoader加載os,管理權交給os算法

系統調用

應用程序主動向操做系統發起請求指令(syscall)。同步或異步chrome

異常

應用程序執行中被動觸發操做系統執行指令。應用程序意想不到的行爲。除以零、訪問未知地址等。同步。應用能夠感知shell

中斷

外設向操做系統發出請求,須要操做系統提供支持。異步。對應用透明編程

陷阱

陷阱指的是當異常或者中斷髮生時,處理器捕捉到一個執行線程,而且將控制權轉移到操做系統中某一個固定地址的機制。現代操做系統是由中斷驅動的,中斷分爲硬件中斷和軟件中斷。而陷阱屬於一種軟件中斷。若是計算機沒有進程要執行,沒有用戶響應請求,操做系統將等待某個事件的發生。而事件老是由中斷或者陷阱引發的windows

雙重模式操做

操做系統爲保證系統正常運行,會提供兩種操做模式:api

  • 用戶模式:用戶進程執行的模式,模式位1
  • 系統模式:系統調用的模式,模式位0

兩種模式不會互相干擾。操做系統須要硬件支持來提供雙重模式操做:當用戶進程進行非法操做(非法指令或非法地址訪問)的時候,硬件會向操做系統發出陷阱信號,致使控制權轉移到操做系統,操做系統結束用戶進程並給出錯誤信息數組

進程

運行中的程序。分爲用戶進程和系統進程瀏覽器

內存管理

內存是cpu和io設備能夠共同訪問的數據倉庫。若是cpu須要訪問磁盤數據,首先生成io調用將數據加載進內存,以後才能直接訪問

虛擬地址

編譯器會應用程序生成的地址

物理地址

實際內存條(主存)和硬盤提供的可用地址

cpu訪問內存數據的過程

  1. cpu中ALU(算術邏輯單元)在運算的時候須要獲取某個虛擬地址的數據
  2. 虛擬地址到物理地址的映射關係會保存在MMU(內存管理單元)和內存中。MMU首先查找本身的映射表中虛擬地址對應的物理地址,若是找不到就去內存查找,直到找到物理地址
  3. cpu向總線發起訪問物理地址的請求
  4. 內存訪問物理地址的數據並經過總線傳遞給cpu

操做系統在其中扮演者預先創建虛擬地址到物理地址映射關係的角色,而且還限制了每一個應用訪問虛擬地址的空間。若是cpu執行某個應用程序時,訪問了不屬於它的空間,就會產生一個內存訪問異常,操做系統會接管並執行相應的異常處理代碼

內存碎片

內存中空閒的,未被使用的空間

外碎片

分配單元之間,沒被使用的空閒空間

內碎片

已分配給該應用,可是該應用未利用到的空閒空間

內存管理

合理的內存管理就是減小這些內存碎片

  • 操做系統爲了加載應用程序,會提早分配一段連續的內存空間
  • 應用程序爲了存儲、訪問一些數據,須要向操做系統發起請求,操做系統爲它分配一段連續的內存空間

簡單的連續的內存分配算法

  • 首次適配:找到第一個足夠大小的空閒塊就立馬分配
  • 最優適配:找到(空間塊 - 需求塊)非負數而且最小的空閒塊。須要排序,容易致使不少小碎片
  • 最差適配:找到(空閒塊 - 需求塊)最大的空閒塊。須要按空閒大小倒序排序,容易致使後面申請的大塊都沒法分配

碎片整理

  • 壓縮式碎片整理:將已使用的內存塊進行移動,壓縮成連續的空間,最後留出大的空閒塊。須要在應用暫停執行的時候才能移動,不然應用訪問內存數據出錯。涉及反覆拷貝操做,開銷較大
  • 交換式碎片整理:若是經過壓縮也沒有足夠內存塊使用,能夠將不活躍應用申請的內存塊換出到硬盤,留出足夠的空間分配給活躍應用

非連續內存管理

  • 優勢:一個程序的物理內存是非連續的,這樣能夠提升內存利用率,減小碎片。而且將程序分紅多個模塊分別進行管理,讓有的模塊能夠被多個程序共享,還能夠對這些模塊採用不一樣的管理方式。
  • 缺點:須要創建虛擬地址到物理地址的映射關係,採用軟件的方式創建性能開銷大,須要依賴硬件方式創建

兩種硬件方案:分段、分頁

分段

將應用分紅多個段:堆、運行棧、程序數據、程序text段。在虛擬地址是連續的,可是映射到物理地址是分離的

分段尋址機制:在分段機制中,要將虛擬地址映射到物理地址,虛擬地址被劃分紅兩個部分,第一段爲segment number,第二段爲segment offset。cpu根據segment number去segment table中定位到該number對應物理內存的base地址,及該segment長度limit。而後經過檢查offset是否小於等於limit,若是不是就觸發異常,若是是該虛擬地址就成功映射到物理地址base+offset

segment table是由操做系統預先創建,並存入硬件

分頁

分段在cpu中使用較少,分頁使用較多

分頁相似分段,也是將內存分紅多個部分

在虛擬內存中,這些部分稱爲page(頁),在物理內存中,這些部分稱爲frame(幀)。虛擬地址由page number和page offset定位,物理地址由frame number和frame offset定位,page number與frame number大小能夠不一致,可是二者的offset必須一致,而且page size和frame size大小一致。

硬件尋址的時候根據虛擬地址劃分出page number和page offset,並經過page table和該table的base地址查詢page number到frame number的映射關係,最後定位到frame number,因爲page offset與frame offset一致,因此最終物理地址就是frame number + page offset

分段與分頁惟一不一樣的地方在於每一個segment的大小不一樣,而每一個page大小相同(1k、4k等)。因此segment table須要記錄[segment number -> 物理內存base地址,segment長度limit]映射關係。而page table只須要記錄[page number -> frame number]映射關係

經過分段或分頁中,虛擬內存是連續的,可是定位到物理內存能夠是非連續的,這樣提升了內存利用率,減小了碎片

page table由操做系統創建

頁表

假設page size爲1k(2^10),64位操做系統須要創建的page table大小達到2^(64-10)=2^54,這麼大的page table cpu和內存都沒法存放,這致使空間開銷大。即便內存能夠存下,每次尋址都要先查page table再查物理內存,涉及到兩次內存查詢,這致使時間開銷大

  • 時間:經過TLB解決
  • 空間:二級/多級頁表、反向頁表

TLB

每次cpu的MMU(內存管理單元)尋址的時候都會查詢page table,這樣致使時間開銷很大。TLB是MMU中包含的一個緩存,緩存了page table的數據,空間很小速度很快

爲了減小TLB查詢miss,應用須要保證訪問局部性

二級/多級頁表

以二級頁表說明

將虛擬地址分紅三部分:

  • p1:一級頁表編號
  • p2:二級頁表編號
  • page offset:頁表offset

內存中創建兩個page table,一級page table中存儲二級page table的base地址,二級page table存儲frame number

尋址方式:

  1. MMU已知一級page table的起始地址,加上p1,定位到一級page table中存儲的二級page table的base地址
  2. 根據該base加上p2,定位到frame number
  3. 最終加上offset,定位到物理地址

這種方式之因此能減小空間,能夠經過64位系統、1k page size狀況來講明:

只用一個page table會致使須要創建大小爲2^54的page table,根據這個page table中的信息判斷虛擬地址是否有對應的物理地址

採用二級page table會讓一級page table成爲二級page table的索引,若是索引不到二級page table無需創建,索引到才須要創建。當虛擬地址遠遠大於物理地址的時候,會極大減小二級page table的item

結合上述結果,可得若是更多級page table會大大減小所需空間,不過也會帶來另一個問題:屢次訪問內存page table導致時間開銷大。這個能夠經過TLB解決

須要爲每一個進程分配多級頁表,以保證進程隔離,進程不會越界訪問其餘進程的虛擬地址。隔離以後,每一個進程看到的虛擬地址可能一致,但映射的物理地址不會相同,這一層經過操做系統保證

反向頁表

多級頁表會致使管理頁表更麻煩,而且大小受虛擬地址影響,並且多級頁表的狀況下須要爲每一個進程分配頁表,因此空間開銷依然不小

反向頁表不一樣,它根據物理地址索引虛擬地址,大小受物理地址限制,而且全部進程共享同一張頁表,因此空間開銷很小。須要區分每一個物理內存對應的應用,就須要引入pid(進程編號)

因爲cpu只能拿到虛擬地址,利用反向頁表的時候,須要遍歷頁表,匹配指定pid和虛擬地址,最終肯定物理地址。至關於遍歷數組的值,肯定索引,時間開銷較大

優化方案

基於hash函數方案:能夠經過傳遞pid和虛擬地址,執行一段hash函數,定位到索引,即物理地址。缺點是設計高效少碰撞的hash算法難度較大,而且訪問hash表會致使多出一次內存訪問,這個能夠經過TLB緩解

虛存技術

內存不夠的狀況下的解決方案之一。將應用使用的內存分紅多個頁管理,當內存不夠用的時候,將應用沒有使用到的頁交換到磁盤,當內存足夠的時候,將應用須要的頁交換到內存。經過操做系統內核和MMU完成

內存置換的時候,須要一些信息,這些信息存在頁表項中

頁表由頁表項組成,每一個頁表項包含

  • 虛擬頁編號
  • 訪問位:表示該頁是否被訪問過(讀寫)。1表示是,0表示否。置換算法優先置換沒有被訪問過的頁
  • 修改位:表示該頁在內存中是否被修改過。1表示是,0表示否。若是被修改過,交換該頁的時候,須要從新寫到磁盤。若是沒被修改過,直接釋放該頁便可,磁盤已經保存該頁內容
  • 保護位:表示該頁的訪問權限。可讀、可讀寫、可執行等
  • 駐留位:該頁在內存仍是磁盤。1表示該頁在內存;0表示該頁在磁盤,訪問到該項將致使缺頁中斷。
  • 物理頁編號

程序局部性

虛存技術將內存置換交給了操做系統,但一樣提出了對應用程序的要求。它但願程序可以保證局部性

  • 時間局部性:一個數據的一次訪問與下一次訪問間隔時間很短
  • 空間局部性:一條指令與下一條指令訪問的數據集中在一個很小的區域

當程序達到時間局部性和空間局部性,就說程序的局部性很好,它能讓內存置換次數更少,使得訪問虛存就像訪問內存同樣簡單、快速

缺頁中斷

當訪問虛擬內存沒法映射到物理內存時,會產生缺頁中斷,流程爲:

  1. 若還有空閒物理頁面,則分配物理頁幀f,則進入步驟4;若沒有空閒物理頁面,則進入步驟2
  2. 經過頁面置換算法,選出物理頁f與其對應的虛擬頁q,若是該頁的修改位爲1,則將該頁寫回磁盤
  3. 修改q對應的頁表項(將駐留位改成0)
  4. 將硬盤中的數據讀到物理頁幀f,並修改對應的頁表項(將駐留位改成1,將物理頁號改成f)
  5. 從新運行被中斷的指令

最優置換算法

局部頁面置換算法

當出現缺頁中斷而且沒有足夠的物理頁面時,須要置換算法保證將一部分頁面寫到磁盤,並騰出相應的空間。

最優置換算法但願保證將要置換的頁面在後面很長一段時間都不會訪問到

不過這種狀況較理想,由於沒法預測將來應用會訪問到的頁面,因此這種方式沒法實現。不過這種算法能夠做爲一個理想評價標準

FIFO置換算法

局部頁面置換算法

操做系統維護一個鏈表,維護使用過的頁信息。鏈表採用先進先出原則,在缺頁中斷髮生時,鏈表表頭的頁會被淘汰。效果較差

LRU置換算法

局部頁面置換算法

最久未被使用的頁優先被淘汰

採用棧或鏈表實現:每次訪問頁面,若是以前訪問過,則替換到表頭或棧頂,並淘汰表尾或棧底的元素。每次訪問頁面都要遍歷一次鏈表或者棧,時間開銷較大。若是採用hash表,空間開銷大

CLOCK置換算法

局部頁面置換算法

將頁組織成一個環形鏈表,當出現缺頁中斷時,指針沿着環形鏈表不斷向後轉動,若是發現訪問位爲1的則將它置爲0,若是碰到訪問位爲0的則淘汰該頁

訪問位是在cpu訪問該頁以後置爲1的,表明該頁最近被訪問過。這個算法至關於給了兩次機會,當須要置換時,會檢查該頁,若是爲1,則置爲0,表示只有最後一次機會留在內存。若是一個頁常常被訪問,操做系統置換檢查時,該位應該老是1

加強CLOCL置換算法

局部頁面置換算法

上述CLOCK算法沒有考慮須要置換的頁面是否被修改過。

  • 若是被修改過,則置換該頁成本較大,須要將頁數據寫出
  • 若是沒被修改過,說明該頁內容已經存在於磁盤,置換成本很小,直接釋放該頁便可

加強CLOCK算法思想是優先淘汰沒有訪問而且沒有寫的頁。它引入修改位,將訪問位與修改位視爲二元組,在環形鏈表中:

  • 若是指針指向頁的二元組爲11,則置爲01(訪問爲置爲0)
  • 若是指針指向頁的二元組爲10或01,則置爲00
  • 若是指針指向頁的二元組爲00,則直接淘汰

LFO置換算法

局部頁面置換算法

淘汰使用最少的頁

這種置換算法有兩個問題:

  1. 須要一個計數器來統計使用次數,這個計數器不斷增加,容易變得很大,須要專門的硬件(內存或寄存器)來存儲,開銷大
  2. 有些應用初始化操做會頻繁加載某些頁,可是以後再也不使用。致使這些頁面計數不少,可是之後不會再用
  3. 比較計數大小的時間開銷較大

第二個問題的解決方案是,定時將計數寄存器右移,保證一直未被使用的數據,最後會指數級衰減

belady現象

給每一個應用分配的物理頁面越多,缺頁率反而越高的異常現象

工做集

一個進程當前正使用的邏輯頁面集合。由二元組W(t,△)

  • t表示當前時間
  • △表示一個時間窗口
  • W(t,△)表示當前時間t以前的△時間窗口中的全部頁面集合
  • |W(t,△)|表示工做集大小,即頁面數

|W(t,△)|能夠量化應用局部性,若是頁面數越大,局部性越差

常駐集

當前時刻,進程實際駐留在內存中的頁面集合,大小等於操做系統分配給該進程的物理頁數,內容取決於操做系統採用的頁面置換算法。

工做集與常駐集:進程不斷訪問內存頁,造成工做集集合,訪問頁的時候會查詢常駐集中頁,若是不存在則引起缺頁中斷

局部與全局頁面置換算法

以前介紹的FIFO,LRU,CLOCk,加強CLOCK都是局部頁面置換算法,只考慮某個進程內頁面置換的狀況。全局頁面置換算法會考慮全部進程進行頁置換的狀況。

爲何須要全局置換算法?

每一個進程工做集不斷變化,程序局部性也在不斷變化,操做系統能夠根據這些信息動態調整常駐集大小,避免浪費或者資源不夠。因此,全局頁面置換算法相比局部頁面置換算法,更加合理

爲何介紹局部置換算法?

既然全局置換算法更合理,爲何介紹局部置換算法呢?由於有的局部算法如FIFO,LRU,也能夠用在全局;有的系統更加依賴局部置換算法來保證部分程序出現抖動不會影響全局系統

工做集頁置換算法

全局頁面置換算法

常駐集只保存工做集中的頁面,全部不在工做集中的頁面都要置換出去。每次應用訪問內存頁的時候,都會進行置換算法

缺頁率置換算法

全局頁面置換算法

思想是根據缺頁率動態調整常駐集大小。當缺頁率太高時,增大常駐集(物理頁幀數);當缺頁率太小時,減少常駐集。保證缺頁率在一個合適的範圍內

實現:

  • t1表示當前缺頁中斷時間,t2表示上次缺頁中斷時間,T表示缺頁率閾值,高於該閾值表示太高,低於等於該閾值表示太低
  • 當t2 - t1 > T,從常駐集中移除不在[t1,t2]時間內的頁
  • 當t2 - t1 <= T,在常駐集中添加缺失的頁

相比較工做集頁置換算法,缺頁率置換算法以缺頁率爲參考依據,工做集置換算法須要在每一個時刻執行算法,缺頁率算法只是在缺頁的時候纔會執行算法

抖動

當進程數愈來愈多,分配給每一個進程的物理頁數愈來愈少,致使常駐集永遠沒法包含工做集,導致大量缺頁中斷,操做系統頻繁進行內存置換,cpu利用率大大下降。這種現象稱爲抖動

抖動出現表明操做系統的負載太高,這種負載每每是過多的進程數或不合理的物理頁數致使的。爲了緩解這種狀況,操做系統須要保證:

  1. 全部進程的工做集總和 = 物理內存大小。若是前者大於後者,會致使物理內存不夠用,常常會出現缺頁中斷;若是前者小於等於後者,說明物理內存足夠空閒,每一個進程能分配到足夠的工做集。
  2. 平均缺頁間隔時間(MTBF) = 缺頁中斷處理時間(PFST)。若是MTBF >= PFST,表示缺頁間隔時間較長,不算很頻繁,有足夠的時間處理缺頁中斷;若是MTBF < PFST,表示缺頁間隔較短,很頻繁,沒有足夠的時間處理缺頁中斷

實際狀況,第一個方案較難實現,每每採起第二個方案

進程與程序

關聯:

  • 進程是正在運行的程序。它擁有獨立的堆、棧、代碼段、數據段
  • 程序是可執行文件,只有被操做系統加載進內存以後才能成爲進程
  • 一個程序能夠衍生出多個進程,每一個進程使用的數據內容都不相同。一個進程可能由多個程序組成。二者是多對多映射關係

區別:

  • 進程是動態的,程序是靜態的。程序是有序代碼的集合;而進程是運行的程序,它擁有用戶態和系統態之分
  • 進程是暫時的,程序是永久的。進程結束以後,它就不存在了;只要硬盤不壞,它存儲的程序就一直存在
  • 進程和程序的組成不一樣。進程不光包含程序,還包含運行中的輸入輸出的數據,以及進程的狀態信息

進程組成

進程包含以下信息:

  • 代碼
  • 數據
  • PC寄存器,存儲下一條執行指令
  • 一組通用寄存器
  • 一組系統資源,如內存、文件系統、網絡等資源

進程控制塊

操做系統用來表明每一個進程的數據結構,簡稱PCB。PCB能夠描述進程的基本狀況和狀態變化的過程,是每一個進程的惟一標識

包含三類信息:

  1. 進程標識信息
  2. 狀態信息的保存區。每一個進程都會利用cpu對通用寄存器、PC寄存器、狀態寄存器、棧指針寄存器作一些修改,這些修改在進程切換以前須要保存下來,以便恢復使用。PCB必須能存儲這些狀態信息
  3. 進程控制信息。 進程調度狀況、進程間通訊信息、進程對內存的使用信息、進程使用的資源、進程與其餘進程的父子關係都存在這裏

通用操做系統會採用鏈表而不是數組來組織PCB,由於進程會不斷建立和銷燬,因此須要不斷添加和刪除操做,採用鏈表開銷更小

進程的生命週期

進程生命週期能夠分爲:

  1. 進程建立。進程建立的三種狀況:操做系統初始化、用戶發起建立進程的請求、進程發起建立進程的系統調用
  2. 進程就緒。一旦進程建立完成,而且初始化完成,它就處於就緒狀態,表示能夠被執行
  3. 進程運行。操做系統會從多個就緒狀態的進程中選擇一個給cpu執行
  4. 進程等待。進程須要等待一些事件完成,會阻塞本身
  5. 進程喚醒。當處於等待狀態的進程所須要的事件完成時,就會被(其餘進程或操做系統)喚醒。一旦喚醒,進程進入就緒狀態
  6. 進程結束。進程會由於這幾種狀況結束:正常退出(自願)、異常退出(自願)、致命退出(強制:訪問非法地址)、被其餘進程殺死(強制:kill)

進程狀態變化

其中須要說明的是Running與Ready之間的狀態轉換:內存中有多個就緒的進程須要執行,當進程A執行時間片用完以後,操做系統會切換到進程B,讓進程A進入就緒狀態,進程B進入運行狀態

進程掛起

進程掛起就是當內存不夠用的時候,將進程換出到磁盤。掛起分爲兩種狀態:

  • 阻塞掛起:進程在磁盤而且等待事件的發生
  • 就緒掛起:進程在磁盤,一旦進入內存就是就緒狀態

掛起涉及到的狀態轉換:

  • 阻塞 -> 阻塞掛起:進程須要更多內存資源時,優先將阻塞狀態的進程掛起,變成阻塞掛起狀態
  • 就緒 -> 就緒掛起:在高優先級阻塞進程和低優先級就緒進程中,優先掛起後者,變成就緒掛起狀態
  • 運行 -> 就緒掛起:當出現高優先級阻塞進程進入就緒狀態,操做系統可能會掛起運行進程,變成就緒掛起狀態
  • 阻塞掛起 -> 就緒掛起:當阻塞掛起的進程等待的事件出現時,操做系統會將它轉變爲就緒掛起狀態

進程激活

進程激活就是將進程從磁盤換入到內存,涉及到的狀態轉換:

  • 就緒掛起 -> 就緒:沒有就緒進程,或者被就緒掛起的進程優先級較高時,會執行這種轉換
  • 阻塞掛起 -> 阻塞:當一個進程釋放了足夠的內存,操做系統會將優先級較高的阻塞掛起進程激活,變成阻塞狀態

進程狀態隊列

操做系統根據進程狀態,來分開管理進程:

  • 就緒隊列管理就緒狀態的進程
  • 阻塞隊列管理阻塞狀態的進程

操做系統根據進程的狀態,決定將它插入哪一個隊列中。當進程狀態變化時,操做系統會從原隊列取出,插入新隊列

  • 根據優先級將就緒隊列分紅多種,優先級高的隊列優先被處理
  • 根據等待的事件類型,將阻塞隊列分紅多種,每一個隊列對應一個事件

線程

輕量級進程,是進程中的一條執行流程。一個進程中的不一樣線程,共享相同的數據區、代碼區和打開的系統資源,可是每一個線程有本身獨立的PC、棧、通用寄存器,以便維護各自的執行狀態。進程是資源分配的單位,線程是cpu調度的單位

操做系統採用數據結構TCB來表示線程,線程與進程同樣,也擁有就緒、阻塞、運行三種狀態,以及狀態之間的轉換關係

優勢:

  • 輕量級,打開、釋放、切換更快
  • 共享數據模型,比進程間消息傳遞更快
  • 共享相同資源,更加節省空間

缺點:

  • 安全性差,同一進程不一樣線程會對共享的數據產生污染
  • 穩定性差,同一進程多個線程,其中一個奔潰會引發其餘全部線程崩潰

例子:

  • 高性能計算每每採用線程
  • 瀏覽器爲了穩定性和安全性,每每每一個標籤頁一個進程(chrome)

線程所需的資源:

用戶線程

由庫函數實現的線程是用戶線程。採用庫來支持線程的建立、銷燬、調度,操做系統並不知道用戶線程的存在

優勢:

  • 線程的操做都在用戶態,開銷小

缺點:

  • 線程執行阻塞操做會block整個進程,由於操做系統只知道進程而不知道線程
  • 進程中一個線程只要不讓出cpu,其餘線程都沒法執行,由於操做系統沒法對這些線程作調度
  • 操做系統只能以進程爲單位分配時間片,最終分到每一個線程的時間片就很是有限

內核線程

由內核維護PCB和TCB

優勢:

  • 不會由於個別線程阻塞其餘線程,由於操做系統會執行線程切換
  • 操做系統可以以線程爲單位分配時間片,更靈活

缺點:

  • 每次線程操做涉及系統調用,須要從用戶態切換到內核態,開銷大

案例:

  • windows

輕量級線程

內核支持的用戶線程,結合了用戶線程管理開銷小和內核線程穩定性高的優勢。

案例:

  • Linux方案:每一個用戶線程對應一個輕量級線程,每一個輕量級線程對應一個內核線程,最終用戶線程與內核線程一對一。這種方案簡單,高效,使用更多
  • Solaris方案:用戶線程和輕量級線程多對多,輕量級線程和內核線程多對一,最終用戶線程和內核線程多對多。這種方案複雜度高,更靈活,可是收益較小
  • 其餘方案:用戶線程和輕量級線程一對一,輕量級線程和內核線程多對一,最終用戶線程和內核線程多對一

用戶線程與內核線程映射關係:

進程切換

進程切換涉及的幾個關鍵操做:

  • 保存進程上下文
  • 恢復進程上下文
  • 快速切換。爲保證速度,通常採用彙編實現

其中上下文主要指進程使用的寄存器,如PC寄存器、棧寄存器、通用寄存器。這些信息在切換以前必須保存,以便以後恢復執行

操做系統爲存儲這些進程,提供了多種隊列:

  • 就緒隊列
  • 阻塞隊列
  • 殭屍隊列

進程建立

  • Windows進程建立:CreateProcess
  • Unix/Linux進程建立:fork/exec,經過fork複製出一個子進程,並在程序中劃分爲不一樣的處理流程,在子進程流程中執行exec重寫當前進程,可是pid不變
int pid = fork();//建立一個進程,並返回子進程id

if(pid == 0){
	//子進程返回值爲0
	exec("program",argc,argv0,argv1,...)
}else if(pid > 0){
	//父進程返回值爲子進程id
	...
}else{
	//錯誤
	...
	wait(pid);//等待子進程結束
}

在fork複製進程的時候,會複製全部進程信息,只有其中各自子進程id不一樣,使得fork返回值不一樣

進程加載

Unix/Linux採用exec加載進程,絕大部分狀況下fork後會使用exec,保證拷貝的子進程可以加載新程序。如上一節代碼,exec會將當前進程全部信息替換爲program進程信息

  • 簡單的fork實現就是拷貝父進程全部數據,可是當子進程執行exec時,這些信息會被替換掉,以前全部拷貝都失去意義,並且開銷大
  • 高效的fork實現會考慮exec帶來的影響。通常只用拷貝所需的基本元信息和頁表項,而非全量拷貝,保證子進程在讀操做的時候不受影響,而且開銷很小。以後exec操做替換全部信息也不會感到惋惜。若是子進程沒有執行exec,也沒有單純只讀,而是作了寫操做,操做系統會採用copy on write技術,在寫以前全量拷貝,保證父子進程有獨立的數據空間

進程等待

wait()用於父進程等待子進程結束

  1. 子進程exit()返回一個值給父進程
  2. 父進程wait()等待子進程返回結果

不一樣次序會有不一樣結果:

  • 1先2後:子進程成爲殭屍進程,父進程wait以後直接返回
  • 2先1後:父進程阻塞,等着子進程完成exit,並喚醒父進程,將exit code返回給父進程

進程退出

exit()用戶進程資源回收

  • 它會返回結果給父進程
  • 釋放資源
  • 若是父進程還存在,當前進程進入殭屍狀態
  • 清理殭屍進程

其中exec的時候可能出現兩種狀況:

  • 進程處於Running
  • 可能須要加載硬盤上的程序,進程會從Running轉爲Blocked

進程調度

從就緒進程中挑選一個佔用cpu的過程,若是有多cpu,還須要提早選出一個可用的cpu

進程調度涉及到上下文切換

進程調度時機,首先須要知足這兩個條件其中一個才能產生調度:

  • 進程由運行狀態切換到等待狀態
  • 進程結束

其次,還須要分狀況討論具體調度時機:

  • 非搶佔系統:

    • 進程主動讓出cpu
  • 可搶佔系統:

    • 進程時間分片用完
    • 進程由等待切換到就緒狀態(表示立刻會搶佔cpu)

長進程:執行時間較長的進程

短進程:執行時間較短的進程

先來先服務算法

進程調度算法之一。優先服務先入隊列的進程

優勢:

  • 簡單

缺點:

  • 若是長進程在就緒隊列前排位置,容易致使平均等待時間過長
  • 若是cpu密集型排在io密集型以前,容易致使io長時間得不到利用

短進程優先算法

進程調度算法之一。優先服務短進程。涉及到兩個技術點:

  • 排序
  • 預測進程執行時長:相似牛頓法求根號的方式,不斷預測並矯正,保證最後逼近真實值

優勢:

  • 平均等待時間較短

缺點:

  • 容易致使進程飢餓(長進程一直沒法執行)

最高響應比優先算法

進程調度算法之一。根據就緒隊列中進程列出以下公式:

R=(w+s)/s

  • w:進程等待時間
  • s:進程執行時間
  • R:響應比

等待時間越長,R越大;執行時間時間越長,R越小。該算法優先服務R最大的進程。可見,它至關於短進程優先算法的改進版

優勢:

  • 平均等待時間較短
  • 防止個別進程無限期等待

缺點:

  • 不支持搶佔

時間片輪轉算法

調度算法之一。指定時間片大小爲N,按前後順序取出就緒隊列中的進程執行,時長不超過N,執行完成以後,取下一個進程繼續執行。取進程的順序與先來先服務一致,可是每一個進程執行時間不得超過N

優勢:

  • 保證每一個進程都能執行

缺點:

  • 若是時間片設置過小,會有大量上下文切換,開銷大,而且平均等待時間較長
  • 若是時間片設置太大,會退化成先來先服務算法

經驗規則:一般設置成10ms,能夠保證上下文切換開銷在1%之內

多級隊列算法

調度算法之一。將就緒隊列分爲多級子隊列,根據每一個隊列具體狀況的不一樣,採用不一樣的算法,是一種綜合使用全部算法的一種算法

多個子隊列之間採用時間片輪轉算法來調度,每一個隊列保證必定的cpu執行時間。

如:兩個隊列,前臺交互式,佔80%時間,後臺批處理,佔20%時間。則每一個執行週期會執行4次前臺進程和1次後臺進程

多級反饋隊列算法

多級隊列算法改進版。多級隊列算法沒有考慮到實際隊列中進程執行時間,有的較長但放在了前臺隊列,致使真正響應快速的進程沒有獲得更高的優先級

將多級子隊列按優先級從高到低劃分,優先級越低,分得的時間片越大,適合執行批處理任務,優先級越高,分得的時間片越小,適合執行交互式任務。執行順序從高到底,高優先級隊列執行完了才執行低優先級隊列,在規定時間片內每執行完的進程,被下放到低一級的隊列,但獲取到了更多時間片

優勢:

  • 優先執行了交互式任務
  • 高優先級的總時間較小,不會致使低優先級隊列飢餓
  • 靈活,自動調整隊列中的進程優先級,每一個隊列能夠採用適合本身的算法

缺點:

  • 實現複雜度較高

這是實際系統會採用的算法

公平共享調度

按用戶組重要程度,給他們使用的系統資源劃分優先級,沒用完的資源用比例劃分

不作詳細介紹

實時調度

有些系統不只要保證功能性,更要保證明時性,但願能再可預測的時間以內完成某個功能。它對吞吐量要求並不高,可是對實時響應要求很是高。根據實時程度,分爲兩種:

  • 硬實時:必須在指定時間內完成功能
  • 軟實時:儘可能在指定時間內完成功能

一個實時任務中涉及的重要概念

系統每每由多個實時任務組成,多個實時任務一般是週期性請求,如圖週期爲5

其中假設週期爲5,最大執行時間爲1,則使用率爲1/5

爲保證調度系統實時可控,須要確立衆多任務調度順序,有兩種方法

  • 靜態優先級調度:事先肯定調度優先級
  • 動態優先級調度:動態調整調度優先級

速率單調調度

任務週期越短(速率越快)的優先級越高

由於任務的週期(速率)是調度以前就能肯定好的,因此它是靜態優先級調度算法

最先截止時間調度

請求的任務中,截止時間越早,優先級越高

任務不一樣,截止時間也不一樣,因此只有處理任務請求的時候才能知道截止時間,因此它是動態優先級調度算法

非對稱多處理器調度

選取其中一個cpu做爲主,進行調度和資源訪問,無需同步,可是沒法利用多處理器

對稱多處理器調度

簡稱SMP,每一個cpu運行本身的調度程序,訪問共享資源的時候會須要同步,同步開銷較大,可是更加通用。多處理器調度實際上是考慮如何將進程分配給cpu,有兩種方案:

  • 靜態進程分配:爲每一個cpu維護一個就緒隊列,進程一旦分配到這些隊列,會一直屬於該隊列,進程一旦執行就不會被切換,至關於將進程綁定給cpu

    • 優勢:調度開銷小
    • 缺點:進程執行時間不一樣會致使cpu負載不均衡
  • 動態進程分配:爲全部cpu維護一個共享就緒隊列,進程會分配給空閒可用的cpu執行,中途會被切換

    • 優勢:cpu負載均衡
    • 缺點:調度開銷(同步、上下文切換)

優先級反置

低優先級進程阻塞高優先級進程的現象

如三個進程A,B,C,優先級A<B<C

  1. A執行,須要訪問資源,加鎖
  2. 切換到C執行,須要訪問資源,等待A釋放鎖,進入阻塞
  3. B開始執行,優先級比A高,搶佔cpu執行,而且長時間執行致使A沒法釋放鎖,C也沒法獲取鎖

這樣B就阻塞了C的執行

優先級繼承

優先級反置的解決方案之一

當低優先級佔有資源而且高優先級進程申請資源時,一旦低優先級進程被阻塞(如A被B阻塞),就讓它的優先級繼承高優先級進程(讓A繼承C的優先級),這樣就能解除阻塞順利搶佔cpu並執行

優先級天花板協議

優先級反置的解決方案之一

當進程佔用資源時,將它的優先級提高爲M(M=全部可能佔有該資源進程的最高優先級),保證讓該進程不會被阻塞

缺點:該方案的缺點明顯,它的濫用優先級提升的功能,當全部進程優先級同樣的時候,這種方案也沒用了

進程併發

優勢:

  • 資源共享,節約成本
  • 速度提高
  • 提升資源利用率
  • 程序模塊化,一個進程能夠分紅多個模塊,併發執行

缺點:

  • 併發會致使數據正確性、一致性受到影響

原子操做

之因此進程併發會出現問題,是由於不少進程操做都不是原子操做,致使執行一半被中斷,並切換到另外一個進程,使得數據正確性和一致性受到影響

原子操做是一組不可中斷的操做,裏面可能涉及多個步驟,要麼所有成功,要麼所有失敗,不可能出現部分紅功部分失敗的狀況

進程交互

進程之間有三種交互狀況:

  • 進程隔離:各進程資源獨立,併發不會致使問題

  • 共享資源:訪問共享資源,會帶來三個問題

    • 互斥:一個進程訪問共享資源,另外一個進程就不能訪問
    • 死鎖:每一個進程擁有一部分資源,須要另外一部分資源才能執行後續的操做,致使互相等待,而沒法繼續
    • 飢餓:部分進程輪流佔用資源,致使其餘進程沒法佔用

    操做系統要知足共享資源的同時又能提升效率,就必須提供一種高效的同步互斥機制

  • 通訊協做:經過互相通訊來傳遞信息

臨界區

將訪問共享資源的一片代碼稱爲臨界區

進入區
臨界區
退出區
剩餘區

臨界區訪問規則:

  • 空閒則入:沒有其餘進程進入臨界區的時候,能夠直接進入
  • 忙則等待:臨界區被其餘進程訪問的時候,等待
  • 有限等待:不會一直等待,能夠設置超時時間
  • 讓權等待:沒法進入臨界區而等待的時候,須要放棄cpu使用權(sleep和while空轉會一直佔用cpu,wait不會)

禁用硬件中斷

經過禁用硬件中斷能夠很好的實現對臨界區訪問的同步,它能夠保證進程不會被中斷,也沒有進程上下文切換,也沒有併發執行。它的思想是經過限制併發、並行,保證進程執行的正確性和一致性

優勢:

  • 基於硬件方案,實現簡單

缺點:

  • 系統低效
  • 臨界區執行時間長會致使後續的進程飢餓
  • 沒有中斷,也就沒法及時響應進程的緊急事件
  • 只適用於單個cpu。能夠保證單個cpu的狀況下進程不會併發執行,可是沒法保證多個cpu的狀況下進程並行執行

現代操做系統提供了禁用中斷及恢復中斷的指令,可是不多使用

Peterson算法

基於軟件方式的實現兩個線程同步的經典算法

思想是提供兩個共享變量,並組合使用,來表明是否能夠訪問臨界區。能夠很好的協調多個線程訪問,而且符合臨界區訪問規則

優勢:

  • 不依賴硬件,徹底基於軟件方法實現。雖然涉及多個共享變量的訪問並不是原子操做,可是依然能覆蓋多線程訪問的各類可能性

缺點:

  • 實現複雜,須要考慮多個共享變量被併發使用的各類可能性,容易出錯
  • 只適用於兩個線程同步,更多線程同步須要將代碼改形成更加複雜的模式

經過編程抽象的一種同步機制,底層依賴於硬件支持,保證一個時間點只能有一個線程訪問共享資源。涉及到一個變量和兩個操做

  • value:鎖佔用狀態,1爲佔用,0爲空閒
  • 獲取鎖:獲取鎖的進程才能訪問共享資源
  • 釋放鎖:釋放鎖後,其餘進程才能繼續獲取鎖
  • 等待隊列:自旋鎖不須要等待隊列,引入等待隊列能夠防止cpu空轉

鎖操做必須保證是原子的。cpu提供了兩個原子性操做,庫函數經過使用這兩個原子操做,來實現鎖語義

cpu提供的原子操做

  • testAndSet(value):簡稱ts。返回value的原值,並將value設成1
  • exchange(a,b):交換a,b內存中的值
class Lock{
	int value=0;
	WaitQueue q;
	
	void lock(){
		while(testAndSet(value))
			block(currentThread);//將當前線程放入阻塞隊列,放棄cpu。同時調度其餘線程;若是不作任何操做,就是忙等待
	}
	
	void unlock(){
		value=0;
		wakeup(otherThread);//將阻塞隊列中的線程喚醒到就緒隊列
	}
}

優勢:

  • 適用單cpu或多cpu
  • 適用任意多線程
  • 能夠對多個資源進行同步控制
  • 簡單易用

缺點:

  • 非公平,容易致使線程飢餓。將線程喚醒到就緒隊列,操做系統會按線程優先級來調度,而非等待時間,會導致部分低優先級線程一直沒法執行
  • 有死鎖風險。由於會有阻塞操做,當多個線程有多個資源佔用時,可能出現死鎖風險

基於鎖方案的同步機制更加經常使用

信號量

經過編程抽象的一種同步機制。由一個整數、兩個方法、一個隊列組成

  • sem:整數。表明資源數量
  • P():獲取資源的方法。實現細節:sem減一,判斷是否小於0,是就阻塞,不然繼續
  • V():釋放資源的方法。實現細節:sem加一,判斷是否大於等於0,是就喚醒阻塞線程
  • q:等待隊列

其中信號量提供給用戶用,但P()和V()方法由操做系統來實現,優先級比應用進程的優先級,不會被中斷,保證了兩個方法的原子性

信號量是一種公平的同步方法,先阻塞的線程先進等待隊列,而且優先被喚醒。相較而言,自旋鎖沒法保證公平

用信號量解決生產者消費者問題

在早期操做系統中使用較多,如今不多使用,由於使用複雜,容易出錯。而且信號量中P是操做系統來實現,優先級高,可能會保持阻塞,造成死鎖

管程

不少現代編程語言(java)使用的一種同步模型,是一種高級同步機制

由如下成分組成:

  • 鎖:保護共享資源,持有鎖的線程才能訪問共享資源
  • N個條件變量:相似信號量中的sem,區別在管程有多個變量。能夠做爲同步、喚醒操做的前提條件。經過這些條件變量,管程不只能實現二元互斥,還能限制線程數量
  • 等待隊列:沒拿到鎖的線程都進入等待隊列
  • Wait:持有鎖的線程進入等待隊列,釋放鎖
  • Signal:喚醒等待隊列中的一個線程

管程解決生產者消費者問題

其中count就是條件變量

其中Wait操做會釋放鎖,避免出現信號量中的死鎖問題,使用相對容易

Henson管程

在T2喚醒T1以後,爲了高效不切換,優先繼續讓T2線程執行(沒法肯定到底哪一個執行),直到T2釋放鎖,T1才恢復執行。java中採用此方案

while(count==n){
	wait()
}

因此上述代碼中,wait的線程被喚醒後,可能仍是沒法執行,致使count的值可能遭到修改,因而必須使用while循環從新判斷一次

Hoare管程

在T2喚醒T1後,T2釋放縮,T1搶佔並執行(肯定T1搶佔)

if(count==n){
	wait()
}

因此上述代碼,wait的線程被喚醒後,會搶佔執行,期間不會有其餘線程修改count的值,因此無需重複判斷

hoare側重於做爲原理講解管程執行流程,而henson才適合用在真正的系統

哲學家就餐

五個哲學家,五根筷子,每一個人兩邊都放了筷子,組成環路。哲學家有兩個操做:

  • 就餐:須要拿到兩邊的筷子,進入就餐狀態
  • 思考:放下兩邊的筷子,進入思考狀態

可能出現一種狀況,全部哲學家拿起左邊的筷子,等着右邊的筷子,最後都沒法進食,活活餓死。這就是所謂的死鎖狀況

解決方案:

  1. 提供服務員,服務員只能給一個哲學家受權,被受權的哲學家才能拿兩邊的筷子,而後就餐。這樣不會出現死鎖,可是同一時刻只有一我的就餐,只須要兩根筷子,另外兩根浪費了
  2. 之因此出現死鎖是由於它們按照相同順序拿筷子,只須要讓偶數編號的哲學家先拿左邊再拿右邊,奇數編號的哲學家先拿右邊再拿左邊便可。這樣不但不會出現死鎖,不相領的哲學家還可同時就餐,保證四根筷子可以同時利用

讀者-寫者問題

有四種狀況:

  • 容許多個讀者同時讀。多個讀者能夠同時進入臨界區
  • 在讀的時候不能寫。讀者進入臨界區後,後面的寫者必須等待
  • 在寫的時候不能讀。寫者進入臨界區後,後面的讀者必須等待
  • 在寫的時候不能寫。寫者進入臨界區後,後面的寫者必須等待

根據讀者、寫者的實現機制不一樣,可能採用不一樣的優先策略:

  • 讀者優先策略:優先讓就緒的讀者立刻執行,可能致使寫者飢餓
  • 寫者優先策略:優先讓就緒的寫者立刻執行,可能致使讀者飢餓

java的讀寫鎖就是利用管程思想實現了讀者-寫者機制

死鎖

多個進程之間互相等待對方釋放資源,而且永遠沒法結束的一種現象

死鎖出現的必要條件:

  1. 資源互斥:至少有一個資源是互斥類型的,不能容許兩個或兩個以上的進程同時訪問

  2. 佔有並等待:至少有一個進程佔有資源並等待另外一部分資源才能完成任務

  3. 非搶佔:資源是不可搶佔的,必須由佔用進程自願釋放

  4. 循環等待:必須存在相似以下現象

    • A,B,C三個進程和一組資源
    • A申請B佔用的資源
    • B申請C佔用的資源
    • C申請A佔用的資源
    • 三者造成循環等待

只有知足這四個條件,纔會出現死鎖

針對死鎖的處理方法:

  • 死鎖預防
  • 死鎖避免
  • 死鎖檢測和恢復
  • 忽略死鎖

死鎖預防

提早預防死鎖,死鎖的必要條件有四個,只要其中任何一個不知足,死鎖就不會出現

  • 資源共享:有些資源沒法共享
  • 避免佔用並等待:避免使用部分資源的同時等待另外一部分資源,須要的時候提早申請全部資源,這樣致使資源利用率降低
  • 搶佔:要保證資源必須是可存儲可恢復的才能搶佔
  • 避免循環等待:沒法避免用戶使用資源的順序,因此沒法避免循環等待

死鎖避免

在進程申請資源的時候動態判斷有沒有出現死鎖的可能,若是有就不容許進程使用資源

算法:當進程請求資源時,系統判斷資源分配後是否處於安全狀態,若是是則分配,不然暫停分配

安全狀態指:

一系列進程P1到Pn,保證Pi申請的資源<=當前可用資源+全部Pj佔有的資源,j<i。若是Pi申請的資源不能當即分配,暫停Pi,等到全部Pj完成

安全狀態與死鎖的關係

銀行家算法

是一種基於安全狀態判斷的死鎖算法

核心思想:每一個客戶會申請須要的最大資金量,銀行會根據你已經佔有的資金,力所能及的將剩餘部分借給客戶。客戶在借完資金後會及時歸還,保證銀行有充足的儲備繼續借款

  • 銀行:操做系統
  • 資金:資源
  • 客戶:進程

數據結構:

  • n:線程數量
  • m:資源類型數量
  • Max:n*m矩陣,表明每一個進程所需的最大資源數量,Max[i,j]表明進程i須要的資源j的最大數量
  • Allocation:n*m矩陣,表明每一個進程已佔用的資源數量,Allocation[i,j]表明進程i佔有的資源j的數量
  • Need:n*m矩陣,表明每一個進程須要的資源數量,Need=Max-Allocation
  • Available:m維數組,表明系統中每種資源的可用數量
  • Finished:n維數組,表明進程是否執行完成(釋放資源)

算法:

  1. Work=Available,將可用資源拷貝到工做空間Work,將Finished元素初始化爲false
  2. 找到進程i,知足Finished[i]=false,Need[i] < Allocable的進程,表示i能夠申請資源,不然執行步驟4
  3. Work += Allocation[i],Finished[i]=true,由於i申請的資源最後會被回收,因此忽略分配過程,直接跳到回收環節。執行步驟2
  4. 當全部Finished元素都是true時,說明發現了安全分配的進程序列,系統處於安全狀態;不然會出現死鎖,不會爲進程分配資源

死鎖檢測

基於銀行家算法的思想,判斷會不會出現死鎖。在完成算法後,存在Finished[i]=false,表明進程i會致使死鎖狀態,稱i爲死鎖進程

死鎖恢復

經過結束進程來恢復死鎖:

  1. 一次終止全部死鎖進程
  2. 一次終止一個,直到消除死鎖

顯而後者更好,可是會根據以下條件考慮該優先終止哪一個進程:

  • 進程優先級:優先低
  • 交互進程仍是批處理進程:優先批處理
  • 進程已執行時間和還須要的執行時間:優先時間短
  • 進程已佔用資源和還須要的資源:優先資源少
  • 終止進程數目:優先關聯進程少

經過搶佔進程資源來恢復死鎖:

將死鎖進程回退到安全狀態,並搶佔它的資源,開銷小,可是會出現飢餓現象——進程恢復後又進入死鎖狀態,繼續被搶佔

進程通訊

簡稱IPC,進程間交互信息

  • 直接通訊:進程A、B,A直接將消息發給B,二者必須都在線
  • 間接通訊:進程A、B,A將消息發給內核提供的消息隊列C,B從C取消息,二者可離線

能夠分爲阻塞與非阻塞

  • 阻塞:同步,A發消息給B,必須等待B收到A才能執行後面的操做
  • 非阻塞:異步,A發消息給B,不用等待也能執行後面的操做

根據通訊鏈路的緩衝容量可分爲

  • 0容量:發送方必須等待接收方
  • 有限容量:發送方能夠一直髮,直到容量充滿
  • 無限容量:發送方能夠一直髮,沒有限制

信號

進程間基於中斷傳遞消息的一種機制。如經過ctrl+c終止運行的程序

原理:應用進程註冊信號處理函數,當出現中斷時,操做系統會根據信號回調信號處理函數。ctrl+c是操做系統默認給每一個進程添加的信號處理函數

缺點是侷限性大,只能傳遞信號類型的消息

管道

進程基於內存文件的通訊方式

在命令ls | more程序中

  1. shell首先建立管道,管道擁有讀寫兩端
  2. 建立ls進程,將它的的stdout指向管道寫端
  3. 建立more進程,將它的stdin指向管道讀端

這樣就在內存中創建了兩個進程的消息通道

消息隊列

內核提供一個FIFO隊列,提供給不一樣進程通訊

優勢:

  • 使用簡單

缺點:

  • 將消息從用戶態傳遞給內核,須要進行用戶態內核態切換,並且傳遞消息的過程就是數據拷貝的過程,開銷大

共享內存

  • 不一樣線程之間能夠直接共享內存
  • 不一樣進程之間共享內存,須要明確設置共享內存段

優勢:

  • 不須要從用戶態切換到內核態,也不須要數據拷貝,開銷小

缺點:

  • 須要用戶層處理數據同步的問題

實現機制:

基於頁表來實現。不一樣進程有本身的頁表,操做系統將它們的頁表映射到同一個物理地址空間,就完成了進程間共享內存

文件系統

操做系統中將磁盤數據組織成文件系統,提供對這些持久化數據的操做

功能:

  • 爲數據分配和管理磁盤空間
  • 管理文件集合
  • 保障數據可靠性和安全性

文件系統須要被掛載才能被訪問,它被掛載的目錄稱爲掛載點

根據文件系統的類型分爲:

  • 本地磁盤文件系統:ext四、NTFS等
  • 網絡/分佈式磁盤文件系統:NFS、GFS等

分佈式文件系統會產生安全性、一致性等問題,比本地磁盤文件系統更復雜

文件

文件系統組織磁盤上數據的方式,並抽象了一些屬性用於簡化這些持久化數據的管理

文件屬性:

  • 文件名
  • 建立日期
  • 類型
  • 位置
  • 大小
  • 建立者
  • ...

將文件分爲兩部分:

  • 文件頭:文件屬性、文件存儲位置和順序,在文件系統中管理。這是文件系統管理文件的基本依據
  • 文件數據:磁盤上的字節數據

目錄

目錄是一種特殊的文件,其內容是文件索引表,表的每一項是二元組<文件名,指向文件的指針>。操做目錄就是操做文件索引表

應用程序都是經過系統調用來訪問目錄

文件別名

讓多個文件名指向同一個文件,看起來就像給文件起了別名

有兩種起別名的方式:

  • 硬連接:A爲B的硬連接,A和B地位對等,都指向文件實體。文件有一個計數,記錄多少個文件名指向它。每增長一個硬連接計數加一,刪除一個硬連接計數減一,當計數爲零時,文件纔會真正被刪除。操做方式:ln src dest
  • 軟連接:A爲B的軟連接,A是一個指向B的「快捷方式」,A存儲了B的路徑。刪除B,A成爲死連接;刪除A,B不受影響。操做方式:ln -s src dest

文件目錄循環

可能出現文件子目錄指向父目錄,致使出現循環目錄的狀況,這種狀況會導致目錄遍歷永遠沒法結束

常見的處理方式是設置一個最大遍歷層數

名字解析

文件系統中的名字解析就是根據文件路徑,讀取文件信息

/bin/ls

解析過程爲:

  1. 讀取根目錄的文件頭
  2. 讀取根目錄的數據塊,搜索bin項
  3. 讀取bin目錄的文件頭
  4. 讀取bin目錄的數據塊,搜索ls項
  5. 讀取ls目錄的文件頭

當前工做目錄

進程每讀取文件的時候,都要從根目錄進行名字解析,會致使效率很低。因此操做系統爲每一個進程設置了一個目錄PWD,表明當前工做目錄。這樣當訪問一些當前目錄存在的文件時,不須要再從根目錄開始遍歷

這種機制提供了一種基於相對路徑來訪問文件的方式

虛擬文件系統

簡稱VFS,是對底層各個不一樣文件系統的一個抽象(各個磁盤文件系統和網絡文件系統),對上層提供一個統一的api(open、close、read、write)

全部文件系統實現不一樣,但有些公共數據結構仍是一致的

  • 超級控制塊
  • 文件控制塊
  • 目錄項控制塊

超級控制塊

簡稱superblock,每一個文件系統有一個,記錄了文件系統相關信息:文件系統的類型、數據塊個數與大小、空閒塊個個數與大小等信息

在文件系統掛載時加載到內存

文件控制塊

簡稱inode,每一個文件有一個,記錄了文件相關信息:文件大小、數據塊位置、訪問權限、擁有者等

在訪問文件時加載到內存

目錄項控制塊

簡稱dentry,每一個目錄項(文件、目錄)有一個,記錄了目錄相關的信息:文件控制塊的位置、父目錄、子目錄等

與文件控制塊不一樣的是,它側重於對目錄信息的描述,並且VFS利用目錄項控制塊將文件系統組織成樹狀結構

在遍歷目錄時會加載到內存

文件系統視圖結構

文件系統組織視圖

文件系統存儲視圖

其中

  • vol:superblock
  • dir:dentry
  • file:inode
  • datablock:數據塊

數據塊緩存

內存中緩存磁盤數據塊的一部分區域

在讀的時候提供預讀取:預先讀取後面的數據塊

在寫的時候延遲寫:寫到緩存就返回,操做系統定時flush

頁緩存

簡稱page cache。因爲虛擬內存是基於頁來管理內存,文件系統基於塊來管理文件數據,頁和塊大小不一樣,須要一個機制統一二者的管理方式

頁緩存實現中屏蔽了底層數據塊的管理,上層統一提供基於頁的管理方式,供虛擬內存使用

在應用進程進行內存映射mmap(將文件映射到內存)或者文件讀寫時,虛擬內存會先訪問頁緩存,找不到就會出現缺頁中斷,觸發對文件系統的查詢,而後再把數據加載到頁緩存

文件描述符

不少文件操做都須要搜索文件,爲了保證只在第一次讀取的時候搜索,操做系統須要在第一次訪問的時候打開文件,返回一個文件描述符,文件描述符就是一個索引,指向打開文件表中的打開文件,操做系統在該打開文件中維護了一些狀態信息,保證之後在操做該文件的時候無需再次搜索

打開文件表

操做系統會建立一個全局打開文件表,同時也會爲每一個進程建立一個打開文件表,其中維護了這些信息:

  • 文件指針:每一個進程都會維護一個讀寫指針,互不干擾
  • 打開的次數:指向全局表的該文件,記錄了該文件被打開的次數,當次數爲0時才事該文件才能被刪除
  • 文件的磁盤位置:指向全局表的該文件,之後每次文件操做都只要從該表(內存)讀取位置便可,無需搜索磁盤
  • 訪問權限:每一個進程維護一個訪問權限信息,如只讀、讀寫等

讀取一個文件的流程:

  • 打開文件,返回文件描述符
  • 根據文件描述符定位進程的打開文件表
  • 根據進程打開文件表定位全局的系統打開文件表
  • 根據全局打開表定位文件控制塊
  • 根據文件控制塊定位文件的數據塊地址
  • 將數據塊地址轉換爲磁盤扇區物理地址
  • 將扇區地址讀到內存buffer
  • 將內存buffer數據返回給應用進程

打開文件鎖

多個進程打開文件的時候,可能會出現併發安全問題

操做系統提供了兩種文件鎖:

  • 強制:打開文件時能夠指定該文件被打開,其餘進程不能打開
  • 勸告:進程根據鎖狀態決定怎麼作

文件分配

當文件須要磁盤空間的時候,文件系統須要爲該文件分配數據塊

經常使用分配算法:

  • 連續分配
  • 鏈式分配
  • 索引分配

分配的時候主要考慮兩點:

  • 碎片多少:因爲數據塊大小固定,因此內碎片已經肯定,這裏考慮碎片主要是外碎片。即數據塊分配給文件後,若是磁盤中有大量較小的空閒塊,就說明外碎片較多
  • 訪問性能:訪問文件數據塊的速度

連續分配

根據文件須要的塊大小,查找磁盤中空閒塊,發現有足夠大小的,就分配給文件

優勢:

  • 實現簡單
  • 訪問性能高

缺點:

  • 碎片多

鏈式分配

根據文件須要的塊大小,找到磁盤中各個空閒塊進行分配,並經過鏈表指針聯繫到一塊

優勢:

  • 沒有碎片
  • 實現簡單

缺點:

  • 訪問性能差

索引分配

根據文件須要的塊大小,找到磁盤中的空閒塊進行分配,並單獨利用一個塊存儲索引這些數據塊

優勢:

  • 沒有碎片
  • 訪問性能高

缺點:

  • 須要單獨的索引塊,若是文件較大,可能須要更多索引塊,開銷較大

實際unix文件系統(UFS)會結合索引分配和鏈式分配組成多級索引分配算法

空閒塊管理

要爲文件分配數據塊,首先得知道全部空閒塊在哪。先來看幾種空閒塊管理機制:

  • 位圖:用位圖表示全部塊,0表示空閒,1表示已分配

    • 優勢:查詢快
    • 缺點:磁盤越大,位圖存儲開銷越大
  • 鏈表:在一個空閒塊中加入指針指向下一個空閒塊,造成鏈表。

    • 優勢:存儲開銷小
    • 缺點:查找快
  • 索引:經過一個塊存儲索引,記錄這些空閒塊的位置

    • 優勢:查找快
    • 缺點:若是表大,須要更多的索引塊,開銷較大

實際系統是組合這幾種方式

磁盤分區

機械硬盤都是經過磁頭進行磁盤尋址,若是磁盤越大,尋址時間越大。因此將磁盤劃分紅多個分區能夠減小尋址時間,提高磁盤訪問速度,可是若是同時在多個分區之間切換也會帶來性能的降低

分區就是一組柱面的集合,每一個分區能夠視爲一個獨立的磁盤

分區組織方式:

  1. 在一個磁盤有多個分區,每一個分區一個獨立的文件系統,提升磁盤訪問速度
  2. 在一個分區有多個磁盤,提升存儲空間

其中第二種方式,在一個分區使用多塊磁盤,能夠基於此方案提高文件系統的可靠性與吞吐量,利用到的就是磁盤冗餘技術

磁盤冗餘陣列

基於上述第二種方案,能夠利用冗餘磁盤提升吞吐量(並行)與可靠性(冗餘)

磁盤冗餘陣列簡稱RAID,是一種基於冗餘磁盤的思想實現的磁盤管理技術,經常使用的有RAID-0,RAID-1,RAID-5等

能夠經過文件系統或者RAID硬件控制器來實現

RAID-0

將數據塊分紅多個小塊,並行存儲在獨立的磁盤上,這種方案能夠提高吞吐量

RAID-1

向兩個盤寫,從任意一個讀,利用其中一個作鏡像盤來提升可靠性。這種基於冗餘盤的思想同時緩解了一個盤的讀壓力,至關於也會提高讀性能

RAID-4

利用一個盤作校驗盤,其餘盤基於RAID-0的方案拆分小塊的基礎上並行訪問,校驗盤的數據是其餘盤數據的校驗和。這種方案能夠保證即便其中一個數據盤壞了,也能基於校驗和和剩餘磁盤來恢復它的數據。同時由於利用到了RAID-0的並行方案,也提高了讀寫性能

RAID-5

與RAID-4思想一致,可是爲避免校驗盤稱爲瓶頸,取消惟一的校驗盤,在每次數據寫入時,將計算好的校驗和輪流存放在全部磁盤上,造成一個分佈式系統的負載均衡算法

RAID-3

RAID-4和RAID-5都是基於塊計算校驗和,而RAID-3是基於位來計算校驗和

RAID-6

RAID-5每次寫都會計算出一個校驗塊,保證最終能夠容忍一個磁盤壞掉。RAID-6則是計算出兩個校驗塊,保證能夠容忍兩個盤壞掉

RAID 0+1

RAID嵌套技術之一

讓兩個磁盤採用RAID-0方案並行讀寫,再利用兩個盤做爲鏡像盤同步數據。安全性、性能較好,成本較高

RAID 1+0

RAID嵌套技術之一

讓兩個盤採用RAID-1方案一個主一個備,再利用兩個盤一主一備,先後二者採用RAID-0的方案並行讀寫。安全性、性能較好,成本較高

I/O設備

能夠分爲三類:

  • 字符設備:如鍵盤鼠標等
  • 塊設備:如磁盤驅動器等
  • 網絡設備:如無線、以太網、藍牙等

各設備有不一樣的I/O實現。根據cpu與這些設備的交互,將I/O分爲阻塞I/O、非阻塞I/O、異步I/O

阻塞I/O

用戶進行讀寫操做後,須要等待設備完成讀寫操做,並返回結果

非阻塞I/O

用戶進行讀寫操做後,不須要等待返回結果

異步I/O

用戶進行讀寫操做後,不須要等待返回結果,可是操做系統完成讀寫操做後會通知用戶

I/O設備控制器

cpu經過北橋與內存、顯卡等高速設備鏈接,經過南橋與I/O等設備鏈接

cpu依賴I/O設備控制器與I/O設備交互,設備控制器結構爲:

  • 總線接口:cpu經過總線訪問總線控制器,總線控制器訪問總線接口;I/O設備產生中斷,響應給中斷控制器,控制器反饋給cpu
  • 硬件控制器:與I/O設備交互
  • 內存映射:內存映射後,存儲映射的內存地址,cpu訪問該內存地址就至關於訪問I/O設備
  • 寄存器:存儲I/O狀態信息,如I/O操做是否執行完成等

cpu與I/O設備交互的三種方式:

  • 輪詢:cpu不斷輪詢I/O設備
  • 中斷:I/O設備經過中斷將事件通知給cpu
  • DMA:I/O設備能夠不經過cpu,直接經過DMA訪問內存,避免cpu忙碌

I/O指令

cpu經過I/O端口訪問I/O設備

內存映射

MMU將I/O設置的存儲地址映射到內存,cpu經過訪問內存來實現對I/O設備的訪問

I/O結構

I/O訪問流程就是從用戶進程上到下的訪問流程,當完成訪問後設備經過中斷,從下到上通知用戶進程

I/O數據傳輸

cpu和I/O設備之間基於兩種方式交換數據:

  • 程序I/O:直接經過cpu指令控制I/O設備交互數據

    • 優勢:簡單
    • 缺點:數據量大的時候會致使cpu忙碌
  • DMA:cpu讓I/O設備經過DMA直接讀寫內存,cpu訪問內存便可獲得這些數據

    • 優勢:傳輸數據的時候不阻塞cpu
    • 缺點:複雜

完成數據傳輸後,設備須要通知cpu,有兩種機制:

  • 輪詢:cpu輪詢控制器寄存器,獲取設備狀態信息,根據狀態進行操做

    • 優勢:簡單
    • 缺點:輪詢間隔短會致使cpu忙碌,間隔長會致使響應延遲高
  • 中斷:設備經過中斷將事件反應給cpu。cpu每執行一條指令後都會進行中斷檢查,發現中斷後立馬執行中斷請求,而後再恢復執行原來的進程

    • 優勢:實時性高,延遲最多就一條指令
    • 缺點:複雜,而且當中斷請求特別多的時候,cpu會花費大量時間響應中斷,開銷大

DMA

設備控制器直接訪問內存的一種機制

基於DMA和中斷的方式讀取磁盤數據的流程:

  1. 應用發起I/O請求
  2. 磁盤驅動請求磁盤控制器
  3. 磁盤控制器讀取數據,並通知DMA控制器
  4. DMA控制器將數據發給內存,併產生中斷
  5. 中斷會通知到cpu,cpu將數據傳遞給應用進程

磁盤I/O傳輸時間

磁盤工做機制

讀取數據其實就是磁頭定位到指定的磁道,而後從磁道讀取指定扇區的內容

尋道時間:磁頭定位到磁道所花的時間

旋轉延遲:在磁頭定位到磁道後,磁盤不斷旋轉,直到磁頭髮現數據所在扇區,這個時間開銷就是旋轉延遲

磁盤I/O傳輸時間=等待設備可用+等待傳輸通道可用+尋道時間+旋轉延遲+數據傳輸時間

磁盤調度算法

是一種優化尋道時間的算法,基於如下前提,該算法纔有意義:

  • 尋道是最耗時的環節
  • 同一個磁盤有多個請求。若是每一個磁盤只有一個請求,那麼沒法優化
  • 大量隨機請求致使性能差

當大量隨機I/O請求到來時,磁頭會前後指向不一樣的磁道,致使尋道開銷較大,使用一種優化的順序減小磁頭須要「走動的距離」,是調度算法須要考慮的

FIFO磁盤調度算法

優先服務先來的I/O請求

優勢:

  • 公平

缺點:

  • 實際使用接近隨機I/O,性能差

SSTF磁盤調度算法

優先處理從當前磁臂移動距離最短的I/O請求

優勢:

  • 總尋道時間短,性能高

缺點:

  • 容易致使請求飢餓,致使磁道距離較遠的I/O請求一直得不到執行

SCAN磁盤調度算法

掃描算法,也成電梯算法,先從一個方向處理全部I/O請求,到頭以後從另外一個方向處理剩餘I/O請求

這種算法緩解了SSTF中的飢餓狀況,可是仍是會出現某個方向磁道邊緣的I/O請求飢餓的狀況

C-SCAN磁盤調度算法

循環算法,從一個方向處理全部I/O請求直到磁道盡頭,磁頭立刻移動到另外一端(中間不處理請求),沿着這個方向繼續處理全部請求

相比較SCAN,緩解了飢餓現象。保證磁道邊緣的請求也能很快獲得處理

C-LOOK磁盤調度算法

C-SCAN會沿着一個方向處理I/O請求直到磁道盡頭,C-LOOK的優化是沿着一個方向處理I/O請求直到該方向沒有I/O請求,其餘都同樣

現代操做系統每每會結合這些算法進行使用,保證尋道時間短的同時,又不會出現請求飢餓的狀況

磁盤緩存

因爲訪問磁盤的速度和訪問內存的速度查了幾個量級,因此須要使用磁盤緩存來緩解這個差別致使的瓶頸

這個緩存能夠採用單緩存和雙緩存

  • 單緩存:有一個緩存區,I/O設備和cpu同時只能有一個進行訪問
  • 雙緩存:有兩個緩存區,I/O設備和cpu能夠同時操做各自的緩存區

訪問頻率置換算法

磁盤緩存須要一套置換算法來保證,常常用的扇區數據被緩存,少用的被置換到磁盤

這種算法結合了LRU和LFO的優勢進行處理,短週期的以LRU爲準,長週期的以LFO爲準

相關文章
相關標籤/搜索