30分鐘讓你了解操作系統基本概念

前言:本文是《操作系統教程(陳懷臨註釋)》的讀書筆記,陳首席是在原書pdf 圖片上註解,字體比較模糊,故我把註釋中覺得比較重要的片段摘錄下來。讀完此文可以讓非技術人員對操作系統有框架性的認識,也可以喚起技術人員記憶中某些概念片段,實際上很多概念我也理解得有點模糊,大家一起學習。

1、OS其實是概念多於理論,技術多於演算法。因此把握OS最重要的是把握概念,特別是概念的層次化。

2、OS的本質是實現了CPU, Memory的虛擬化。現代的虛擬化技術是再次虛擬化,實現了OS的虛擬化。

3、在經典Unix下,kernel是共享的,因此必須互斥。kernel屬於每個(each)32bit進程地址空間的一部分,例如3~4G部分。

Advertisements

4、Page on demand 是理解VM虛擬內存的Rule 1(Swap)。

5、在經典 OS設計中,例如Unix, 「Everything is a file」 是非常重要的設計原則。任何一個外設,最後都通過文件系統來表達。一個通過open得到的文件句柄可以唯一的定位一個設備(塊設備or字元設備),並可以通過文件的 read/write來操作。

6、初學操作系統的大學生通常會對文件句柄(File Handler)有點迷惑。可以這樣理解。就是open的時候,操作系統為你構建一個表

項的數組的下標。這樣也就理解了一個進程可以打開的文件數目是有上限的。為什麼?數組的大小是固定的,除非改參數。

7、OS最重要的概念就是進程( Process)。可以理解為是操作系統「管理」的最小單位。虛存(VM),文件( File)都屬於(Belong to)這個進程的domain。例如,屬於哪個進程的。進程就是一個在運行中的程序,通常是一個ELF的載入。

Advertisements

8、學習文件系統的時候,不要去糾結驅動程序的實現。類似談戀愛,非要大家都坦白從幼兒園開始的情史,是大家彼此過不去。要學會「透明」。概念到文件系統,就剎住。否則,為了理解文件系統,非要把 INT13通讀,是沒有必要的。文件就是文件。

9、文件系統最重要的是控制塊( Control Block)。要知道數據(例如,512B)在硬碟哪個地方。而且要靠指針串起來。例如,早期DOS的FAT 表都是這個目的。在現在分散式文件系統中,稱為 metadata。目的都一樣:在哪裡。metadata或者control block失效了,數據都無法定位了。

10、基礎 教材通常會有意識 的凸顯概念。其實任何概念本身就是抽象和總結 出來的。什麼是 「 虛擬處理器」。說白了,就是每個進程數據結構里的 CPU 相關寄存器的值。那就是對於那個進程而言,她的虛擬處理器。虛擬內存?就是她的,例如,頁表和 MMU的設置。

11、初學 OS的同學不要去過分理解虛擬處理器這個概念。還是應該從經典分時系統出發。現代 OS的本質是分時。其他都是演變出來的。分時就是大家皇帝輪流做。因此下台的時候要保存一些狀態。等下次輪到時,從上次斷的地方重新來。

12、輸入輸出( I/O)的訪問必須串列化(Serialization),否則就亂了套。why?寫過驅動就知道,控制設備的那些 control register(控制寄存器)還沒有完成一個操作,如果被覆蓋,設備就死機或者 reset了。併發是 CS許多演算法的目標,但底線是:和串列語義要一致。

13、操作系統另外一個重要任務是參與和指導 CPU設計。現代silicon design從來都是co-design。否則,硬體工程師都不知道在幹嘛。不能畫電路圖玩吧。真正懂一個 silicon的必須包括OS architect。這也是為什麼 OS是計算機科學 or/and工程的美麗之花。

14、在單 CPU的年代,除了中斷(時鐘,外設),一個計算環境不存在併發。 OS做調度也是在幾個固定的點,例如, timer,syscall ,wait for I/O 等。

15、MultiTasking 的本質就是大家共享資源例如, CPU。例如,通過分時,或者是主動退讓( Yield)。多道( Multi Tasking)和多重(Multi Processing)處理的區別是: multitasking就是一個CPU,例如。 multiprocessing是多個CPU。現在的多核,多(硬體)線程都屬於這個範疇。 MultiTasking/SingleCPU本質上還是串列化的(Serialized)。

16、在學習操作系統的時候,一個重要的概念是傳統操作系統內核是獨佔,不可剝奪的, Kernel is not preemptive。這個概念的理解把握對閱讀源碼,理解Unix/Linux 的演化是至關重要的。對鎖機制,鎖粒度的優化也是最重要的。

17、用戶態/核心態的本質是: 保護。保護什麼? Kernel的全局變數。為什麼? Kernel是共享的。每個進程,例如, 32位系統Linux,是4G空間。3G用戶+ 1G核心 =進程。因為是共享的 kernel,所以需要互斥。否則,全局變數用一半就被沖了。

18、理解 kernel空間是PART OF 一個進程空間,是對現代操作系統把握最重要的概念之一。例如,經典 OS有一個重要的statement:kernel是沒有context的。什麼意思? kernel不存在生命。是屬於一個進程的,而且是共享的。

19、系統調用是操作系統里略微難理解的一個概念。其實就是通過一個特殊指令,使得 CPU 陷入到異常處理,然後通過查表(事先填好),最後調用相應的 kernel庫函數。(在經典os里), kernel就是全局變數+函數。寫系統調用時,要注意的是對參數傳遞的約定要比較清楚。

20、操作系統的發展經歷了單一內核( Monolithic Kernel)和微內核(Micro Kernel)的學術爭論。最經典的是 Linus和操作系統泰斗Andres T 1992年的辯論 (–Torvalds_debate )。 現在基本上是 convergence,融合了。特別是在虛擬化技術的今天。

21、進程是最小管理單位;( System Scope)線程是最小調度單位。同一個進程的線程序共享內存,例如全局變數。通常說的線程在kernel里對應一個調度object,通常稱呼這樣的 thread叫做System Scope。如果是 Appliacation Scope,叫做用戶線程,在kernel里不存在 entry

22、在理解操作系統的時候,內核( Kernel)是屬於一個進程(Process)空間的一部分 是一個重要的概念。你編的代碼+內核 構成了一個進程空間。

23、操作系統從過去的 Monolithic OS與Micro Kernel 的學術和工程對立,發展到互相融合。特別是最近的虛擬化技術的發展,使得已經無人再去糾結這些結構之爭。 CPU,多核技術的發展也是導致這些區別淡化的重要原因之一。

24、學習 OS的時候,會接觸CPU,例如 x86. 其實x86 不太適合做 CPU教材例子。 IA32為了支持許多歷史設計含有了許多老東西,例如段地址等。現代 CPU,包括Intel ,都已經是採用 Flat Memory結構。學生們沒有必要去知道和理解之前的技術。應該直接一步到位。

25、中斷/異常處理是掌握一個 CPU重要的部分。不同的CPU實現都有細微的區別,但本質都類似。 保護現場,處理中斷/異常,根據情況決定是恢復現場執行,還是 reboot CPU。

26、信號在 Unix中比較繞,是非同步的通知,進程之間通過互相發 kill。也可以是 kernel發給一個進程。有的signal不能被捕獲,進程必須消亡;有的可以自己接管,接著運行。看是否有 signal的時機需要很清楚:非同步方式:在系統調用,中斷返回的時候。

27、如圖所示, 操作系統從中斷,異常,或者系統調用進來,要結束的時候,都存在一個檢查點( checkpoint),看看是否需要調度,是否需要處理軟中斷( signal)。

28、中斷處理程序要求的是快速。因此 Linux里有一套完整的Bottom Half的機制來做優化,把不存在重入危險的,不是那麼急需立刻需要處理的,可以通過 Bottom Half的一些手段,來「延遲 」執行。從而使得整體系統併發度提高。早期 BH,TaskQueue 機制都已經不用了。

29、在學習 2.2中斷技術方面,可以不要太陷入 Linux獨有的中斷技術細節中。大概了解一些概念就可以了。把握兩個重要的概念:中斷上下文;進程上下文。中斷處理程序需要快,然後迅速開中斷,防止系統堵塞。這是Linux各種各樣的 Bottom Half機制的由來。

30、傳統 Unix的內核是非剝奪式的調度( non preemptive),目的是簡單從而保證內核數據結構一致性(內核是各個進程共享的地址空間)。現代OS,如 2.6之後的Linux ,可以支持內核 preemptive schedule了。目標是支持高併發系統。

31、fork, pthread_create 最後都是調用clone函數,傳遞進去的參數不同而已,子進程/線程在內核中都是產生一個task_struct 元素。"CLONE_THREAD"參數可以告訴clone調用,這個新產生的object是個thread邏輯。從而在thread_group 里會把這個新產生的object加入,作為一個線程來對待,但這種對待是一種邏輯理解而已。

32、例如,一個時間很長的讀磁碟的操作。在阻塞sleep的時候如果是可中斷的,另外一個進程可以發signal,這樣這個進程就能夠從這個讀數據的系統調用中退出來了。

33、為什麼需要線程( thread)來支持併發?都用進程不就可以了嘛?因為屬於同一個進程的多個線程是共享全局變數的,共享內存的,可以合作來完成一個任務。而如果拆分為多個進程,通常就需要 IPC通信才能完成這樣的任務。這就是線程的好處。

34、

a、調度演算法學習中要注意「死鎖 」(deadlock )與」餓死 「(Starving )的區別。餓死,就是低優先順序的任務一直無法得到cpu,一直有高優先順序的任務佔用cpu。

b、Hard Realtime不一定調度快,是指調度系統保證不錯過 Deadline;Soft RT不一定慢,是指調度系統保證錯過 Deadline。

c、有興趣的同學看看NASA的Mars Lander 的優先順序翻轉的事故。(這往往出現在一個高優先順序任務等待訪問一個被低優先順序任務正在使用的臨界資源,從而阻塞了高優先順序任務;同時,該低優先順序任務被一個次高優先順序的任務所搶先,從而無法及時地釋放該臨界資源。這種情況下,該次高優先順序任務獲得執行權。)

35、Linux 2.6的調度是一個分水嶺:支持 Kernel內部可剝奪。支持SMP下O(1)演算法。忘卻具體技術細節,把握: 1. 只要數據結構不存在非一致性,就可以開中斷和支持被剝奪調度,否則通過鎖來保護。 2. 多個Queue一定好於一個 Queue。每個處理器有一個任務隊列。

36、現代multiCpu系統許多採用 CPU Affinity的調度方式,就是把task固定分配給某個或某些cpu上。

37、一個應用系統的設計應該是event driven。沒有事情的時候,任何線程不能去空轉,應該block等待在一個事件上。

38、同步是為了協同工作。通信分為:共享內存(memory)方式 和基於消息( message)方式。通信可以來實現同步。例如, send/recv 。死鎖和餓死都是調度要避免的。

39、學習同步和併發控制時,要注意幾個要點: 1. 同步原語都是等價的。2. 為什麼需要原子性?因為,一個簡單的 value++在指令級別時需要3條指令才能完成:從內存中 Load;寄存器操作加一。 Save 到內存中。在 3個指令之間,中斷可以任意發生。形成併發。

40. 同步機制可以通過 Sem(信號量)。但語義較低。需要在共享內存模式下(例如,多線程),寫比較難的控制代碼。容易出錯。管程(Monitor)是一等價的同步機制。把共享數據和訪問的代碼封裝為對象。提供一個一致的同步 API介面。語義友善。Java等編程語言對 Monitor機制的支持已經很完善並被廣泛使用 例如」Synchronized」的關鍵字的使用。

41、Monitor是一個很有用的機制,特別是在面向對象的程序語言中,都提供了相應的機制。其特點是:通過 sem,mutex的封裝,使得程序員不需要過多的關心低級同步原語( raw primitives)的使用,從而可以在比較高的語義上把握同步,並專註其應用問題本身。

42、System V IPC 通信機制是實現多進程之間通信和同步的重要手段。例如,message queue, shared memory,pipe等。其重要前提是:不同地址空間上的多進程之間的通信和數據交換。 System V的IPC用的比較少了。重要原因是:多線程的同一進程編程模型的流行。

43、DeadLock , LiveLock, Starvation都是在併發編程中需要注意的事情。DeadLock需要避免進程之間互相要鎖然後都進入了等待睡眠的狀態;LiveLock要避免雖然各個進程不都在睡眠狀態,但都在原地抖動 停止不前;例如,吃飯時互相謙讓誰先動筷子 結果誰也沒有吃在無解的謙讓;Starvation 餓死的場景很直接,避免資源的不公平利用 例如 不能某些任務總是獲得資源 有些任務即使長期在等待下 卻沒有被分配到資源。

44、

a、Sem和Spinlock的用法區別在於:如果等待資源時間短和可預期,可以用自旋鎖;否則用 Sem,通過睡眠/喚醒來處理。 Sem由於涉及隊列操作,系統存在不確定的延時效率問題。

b、在多核多CPU情況下,關中斷只能排除當前 CPU的併發,只有通過另外一個全局自旋鎖的介入,才能封住其他 CPU的競爭。

45、編譯和鏈接之後的可執行程序ELF中的地址都是虛擬地址,或者說邏輯地址。在運行的時候通過載入,地址轉換,來確定具體的物理地址。cpu指令的執行基於虛擬地址(邏輯地址),是可以通過不連續的物理頁面,「營造」成一個連續的邏輯空間的重要保障機制。邏輯地址必須是連續的,物理地址可以是page和page散開的。

46、掌握現代操作系統內存管理系統時,可以把握幾個基本知識點。

a、了解ELF展開后的格式。 TEXT,DATA /BSS/ Stack/Heap 的關係。

b、任何一個 CPU的load /store操作都是基於邏輯(或者說虛擬地址),通過MMU轉換一次,成為物理地址,完成「」定位。

47、

a、連續地址空間管理,通常也可以理解為 「堆管理」-Heap。也可以邏輯地址的堆管理,例如進程的 Heap。也可以是一塊連續的物理地址空間,例如,Linux Kernel為Slab分配器提供連續物理頁面的內存。

b、內存管理要注意兩種碎片: External Fragment(一段時間過後無法分配連續的大片內存) 和Internal Fragment(分配的內存比實際需要的大很多)

48、

a、基於4K大小的頁面( Page)的分配粒度太大,Linux Kernel的Slab機制就是為了實現細粒度內存頻繁分配和釋放的一種 memory pool的機制。 (2). 通過架在基於 Page的Buddy演算法內存管理之上, Slab可以不需要頻繁的把常用的數據結構來來回回放回 HEAP里,從而提高了效率。

49、進程切換的時候,要切換頁表基址寄存器,不同的進程有不同的頁表。基於頁表的虛--實轉換是一個「演算法」,是一種mapping,把相應的bits拿來當索引index。不同進程的虛擬地址Va, Vb可以在各自的page table 里指向同一個物理地址,比如父子進程共用代碼段。

50、

a、每個進程都可以有相同的虛擬地址,例如 Va。因此每個進程都必須有自己的頁表,從而無歧義的完成虛實轉換。

b、多級頁表可以使得頁表空間不需要連續物理塊,例如,二級頁表,可以Page by page的分配。

c、通過進程ID,可以避免全局頁表項目的二義性。

51、分段管理與分頁管理是區別和聯繫是:段是應用編程可感知的;頁是應用不感知的,段是早期,例如 intel 80286之前的內存管理;80386之後有了分頁( Page)了。可以「基於分段的分頁內存管理 」。使得在段的基礎上再加入頁面機制,使得內存使用粒度更加小。沒有分頁之前, Intel LDT的目的類似之後的Page Table。每個進程有自己

的LDT從而管理自己的物理內存。全局的上通過 GDT,各個進程之間共享。有了分頁后,段基本上不用了,通過把 seg selector都設為0,大家都在一個段上,從而,例如, Linux,都(只)用分頁機制了。

附圖是一個比較好段和頁機制的關係圖。在段做一次映射之後(通過寄存器索引做一次 LDT和GDT 查表),如果頁機制打開的,查表出來的地址不被當作(not treated as)物理地址而是再做一次基於 Page Table的查表。然後出來的數據才與 offset合併為物理地址去內存取數據。

52、現代 CPU,例如,Power, PowerPC,MIPS ,ARM,都沒有段(segmentation)機制,而是直接採取不需要編程感知的 Paging虛擬內存機制了。段可以認為是 x86/IA32的一個過渡歷史技術了。

53、Intel CPU 的段模式不能關閉。那麼如何無縫的略過,只用頁機制呢? 是通過把 CS,DS等段選擇符預先設置好(參閱宏定義)。然後把GDT裡面的描述符都手工設置基址為 0,大小是4G。由於基址為 0,通過段機制出來的邏輯地址就沒有受到任何影響,完整的進入 Page機制轉換。

54、技術的發展都是演變的。 8086和80286 是16位機 GPR)。地址匯流排是20位和24位。要通過段 reg+Offset來「拼湊 」一個20/24的物理地址。 386是32位機器了。清一色 32位;有了Paging部件。段部件的偏移量也是 32位。所以只要段基址為0,就可以使用基於 Paging的Flat 內存模型。

55、Paging on Demand是現代通用操作系統 VM管理重要的機制。是一種滯后演算法,當需要時來完成虛擬頁面( Page)和物理頁框(Frame)的分配,提高效率。但數據通信系統中,為了避免 Page Fault帶來的延遲和不確定性,往往是事先完成頁框的分配從而確保報文處理的實時性。

56、頁面替換演算法只有知道未來頁面使用情況,才能達到最優。所以,OPT(OPTimal Replacement )是一個理想。現實中,有 LRU和相應的近似演算法( NRU,NFU ),FIFO, SCR,Clock 和各種變種。其中 LRU和Clock比較好。在CPU的cache設計中,晶元的 cache set的演算法說Pseudo-LRU。LRU代價比較大。需要維持所有頁面使用情況來定位 「最近沒有被使用的頁面」。例如如果有 4個頁面其使用情況時4!= 24種。如果是8個頁面,使用順序有 40320種。想想256個頁面,代價太大。現實系統中,需要實時的,多採用一些近似演算法,例如「儘可能最近沒有使用的」。

57、在CPU的 Cache替換演算法中,常採用Pseudo- LRU。就是一個近似演算法。 「差不多就行了」。換出去的一定不會是最近剛用的,但確實可能不是最不用的。如圖, 在 ABC都是hit引用之後,如果有 miss,精確LRU演算法應該是把 D換掉[D就沒有用過]。但如果是 PLRU演算法,會換了A。

58、局部頁面替換演算法概念很直接。就是每個進程的頁面替換不影響其他進程的。這樣可以防止系統的顛簸。 Working set的變種叫做Aging演算法。目的都是一個,逐步收斂和定位一個被替換的頁面,例如某個演算法中衡量參數的最小值。Aging中每次右移一個bit,就是一種衰減過程。

59、內存管理與 CPU聯繫比較緊密。不同的CPU都略微不同。對通用系統而言, Paging on demand;copy on write是操作系統演算法層面比較常用的。但對專用系統並不合適;另外,由於啟動虛擬到物理的映射,使得操作系統存在一個機會幹預內存的分配,保護,從而可以指導策略。

60、「Everything is a file」 是現代操作系統的一個重要概念。通過文件系統的抽象和介面來屏蔽設備多線性。理解設備時,要站在匯流排角度看:CPU和其他設備,例如 ASIC晶元,都是設備。都具備計算處理能力。需要和內存打交道,大家共享匯流排。

61、設備通常是 Memory Based I/O。控制Reg和緩衝區被映射到CPU地址空間,例如通過PCI。讀寫控制寄存器和緩衝區通常與 DRAM內存一樣。通常設備地址 map到高端地址區域。通信系統里,還要事先設置一些cache屬性等,例如,noncacheable。總之,通過系統匯流排控制器或者MMU存儲子系統部件來調控。

62、RAID磁碟陣列是通過多個小的廉價的磁碟的組合,可以比一個單一的昂貴的大磁碟提供更好的性價比。例如併發的操作和容錯。 RAID 0是數據分佈; RAID 1是備份鏡像;之後的都是有校驗糾錯磁碟的。 RAID 6是基於數據塊和分散式存放糾錯,可以支持 2個磁碟壞還正常工作。

63、Unix-like文件系統一個重要概念是: "Everything is a file,except process". 除了進程都是文件。如何把進程與文件聯繫起來?抽象化。通過進程文件打開表,指向系統文件打開表open(文件)調用返回的id其實就是進程文件打開表的數組下標。其中一個重要數據結構是 inode:每個文件對應和只對應一個 inode。1:1。通過 inode數據結構里的指針可以定位文件的數據塊 s。通過inode的 #,可以在磁碟里通過讀寫相應的 inode數據。第一個 inode數據跟在Boot( 1024Byte),SuperBlock( 1024)後面。 inode數據結構里除了指向數據塊的指針( 15個)之外,還含有許多MetaData控制信息。MetaData是文件系統常用的一個辭彙。 MetaData就是「Data that Describes Data」 。描述數據的數據。這個詞來源於以前圖書館里的卡片,卡片上的數據除了書的簡單信息之外,有描述圖書館的書在幾樓,那個書架上的索引,從而同學們可以在相應的書架上找到想閱讀的書。

64、系統文件打開表是一個共享的數據結構,可以使得進程之間對一個文件( inode)共享成為可能。兩種方式: 1. 父子進程之間指向同一個系統文件表的元素 共享對一個文件的操作,包括當前讀寫的偏移量。 2. 不同進程之間通過不同系統文件表表項指向同一個 inode(文件)。

65、「系統來自演化」。 Linux文件系統從最開始依託MINIX的簡單文件系統,然後從早期 Unxi File System(UFS)開始演變,歷經 EXT(Extended File System ,開始支持VFS Interface), EXT2,EXT3,EXT4和BtrFS等。不斷優化。其中 EXT3是一重要的飛躍,支持卷( Journal)。

66、操作系統的安全等級規範最開始是 NSA發布了一個橘皮書規範TCSEC,定義了5個安全等級。 TCSEC(1983年-1999年)現在已經被CC(Common Criteria)和 FIPS等安全規範逐步取代。CC定義了一個軟體產品如果需要賣入到敏感部門所需要通過的相關需求。

67、LSM:Linux Security Modules( LSM)是Linux領域在可信計算方面的工作,其中 NSA主導的SELinux(Security Linux)是基於LSM的一個分支,並已經在2.6進入主線。總體而言,安全的 Linux的基本框架是在進程需要獲得任何核心資源的時候,需要得到相應的許可權和資格檢查。

68、加密演算法本身是一個學科,操作系統範疇接觸一些概念即可。對稱和非對稱加密( aka,Public Key )演算法各有優缺點。可以單獨或者混合使用,例如SSL。基本流程如下:利用非對稱加密演算法,成功協商(交換)對稱秘鑰(瀏覽器與 web伺服器),然後在對稱演算法下交換數據。

69、在操作系統的安全控制中, 3A是關於認證(Authentication),授權(Authorization)和記錄(Accounting)的統一安全監管範圍。Authentication:你是誰,允許訪問否? Authorization:你訪問的許可權和範圍是什麼? Accounting:你訪問期間,都幹了些什麼。

70、網路與分散式系統的界限比較模糊。共性是:都是基於鬆散式互聯架構的拓撲,例如,基於乙太網。 分散式系統比較強調資源(Resource)的透明性(Transparent),例如,一個提供的服務在哪個網路的節點上,對服務的請求者是透明的。

71、分散式系統有兩個不能完全統一的目標: 1.資源使用的透明性; 2. 鬆散式的并行計算。過去 20年來谷歌等互聯網公司成功的把第 2種模式良好的實踐。而經典的追求資源透明性的系統並沒有成熟和普及。 「犧牲透明性,追求并行性 」是現代分散式計算的一個折衷( Tradeoff)。

72、RPC為分散式系統提供了重要的局部函數調用語義,使得應用不需要過分關注網路細節,例如網路編程。 RPC變種有Java/RMI,OMG/CORBA和一些基於承載的 RPC, 例如XMLRPC。不管通信是基於L3的 TCP,L7 的HTTP,目標都一致:局部函數調用語義從而簡化分散式編程模型。

73、類似 RPC,DSM 是為了給應用程序提供一個類似局部訪問內存的編程模型。通過一個數據一致性演算法,保證各個 CPU/節點看見一個一致的內存空間。 UMA:多個CPU直接能夠通過內存匯流排訪問內存。 NUMA:通過互聯網路(例如, infiniband)的拓撲。通常NUMA也預設指ccNUMA。

74、分散式系統: 1. 不存在一個全局的時鐘。 2:任何一個時刻不存在一個節點,能知道那個時刻的全局系統狀態。原因是:消息傳遞有時延。Lamport(2013 年圖靈獎)邏輯時鐘演算法精髓是:通過收發消息這天然的同步點,把無序的分散式事件,映射到整數集合上,從而自然排序。

Advertisements

你可能會喜歡