作者簡介:
程磊,某手機(jī)大廠系統(tǒng)開發(fā)工程師,閱碼場榮譽(yù)總編輯,最大的愛好是鉆研Linux內(nèi)核基本原理。
目錄:
一、計算機(jī)簡介
1.1 什么是計算機(jī)
1.2 計算機(jī)發(fā)展史
1.3 計算機(jī)的二元結(jié)構(gòu)
二、計算機(jī)硬件體系結(jié)構(gòu)
2.1 圖靈機(jī)模型
2.2 馮諾依曼結(jié)構(gòu)
2.3 現(xiàn)代計算機(jī)結(jié)構(gòu)
三、計算機(jī)軟件體系結(jié)構(gòu)
3.1 系統(tǒng)軟件
3.2 應(yīng)用軟件
四、操作系統(tǒng)組成結(jié)構(gòu)
4.1 內(nèi)核
4.2 OS庫
4.3 OS進(jìn)程
五、操作系統(tǒng)本質(zhì)解析
5.1 操作系統(tǒng)的目的
5.2 操作系統(tǒng)的作用之一
5.3 操作系統(tǒng)的作用之二
六、計算機(jī)運行模型
6.1 CPU運行模型
6.2 進(jìn)程調(diào)度模型
6.3 軟件體系結(jié)構(gòu)
一、計算機(jī)簡介
在講解操作系統(tǒng)之前,我們先從整體上講一下計算機(jī),再從硬件講到軟件,最后再講操作系統(tǒng)。
1.1 什么是計算機(jī)
我們生活中幾乎到處都能接觸到計算機(jī),從我們?nèi)粘J褂玫氖謾C(jī)、平板,到辦公使用的筆記本、臺式機(jī),到銀行的ATM機(jī),到各處可見的監(jiān)控設(shè)備,還有我們平時看不見但是我們?yōu)g覽的網(wǎng)頁其所在的服務(wù)器,還有微信、抖音等我們?nèi)粘K玫腁PP它們所在的服務(wù)器,等等,這些都是計算機(jī)。如果沒有了計算機(jī),我們的生活將難以想象。那么究竟什么是計算機(jī)呢,這個還真不好下定義的,那我們就來看一下百度百科對計算機(jī)的定義:計算機(jī)俗稱電腦,是現(xiàn)代一種用于高速計算的電子計算機(jī)器,可以進(jìn)行數(shù)值計算,又可以進(jìn)行邏輯計算,還具有存儲記憶功能。是能夠按照程序運行,自動、高速處理海量數(shù)據(jù)的現(xiàn)代化智能電子設(shè)備。計算機(jī)的應(yīng)用非常廣泛,從我們?nèi)粘W畛R姷呐_式機(jī)、筆記本到手機(jī)平板都是計算機(jī),而且大到服務(wù)器、超級計算機(jī),小到各種嵌入式設(shè)備也都是計算機(jī)?,F(xiàn)在我們對計算機(jī)既有了感性的認(rèn)識,又知道了的它的權(quán)威定義,那么計算機(jī)是怎么產(chǎn)生的呢,下面我們來看一看計算機(jī)的發(fā)展史。
1.2 計算機(jī)發(fā)展史
計算機(jī)的發(fā)展史從概念上最早可以追溯到結(jié)繩計數(shù)、手指頭計數(shù),有了計數(shù)然后我們就有了加減乘除各種計算需求。但是人類天然的計算能力不太行,于是便開始創(chuàng)造工具、使用工具進(jìn)行計算。最古老的計算工具當(dāng)數(shù)中國的算盤了,算盤運用熟練的話可以使加減運算的速度大大加快。后來歐洲人發(fā)明了計算尺,通過對數(shù)方式把乘除運算轉(zhuǎn)換為加減運算,使得乘除的計算速度有了很大的飛躍。歐洲在文藝復(fù)興和科學(xué)革命之后,很多科學(xué)家都想發(fā)明一種通過齒輪和力學(xué)原理來驅(qū)動的機(jī)械計算機(jī),最出名的當(dāng)數(shù)帕斯卡發(fā)明的加法器了,可以進(jìn)行6位數(shù)的加減運算。與牛頓同時期的著名數(shù)學(xué)家、哲學(xué)家萊布尼茨在帕斯卡之后發(fā)明了乘法器,可以進(jìn)行加減乘除開方運算。萊布尼茨的理想遠(yuǎn)不止于此,他一直想把邏輯思維轉(zhuǎn)化為數(shù)學(xué)運算,并且用機(jī)器實現(xiàn)邏輯運算。雖然在當(dāng)時沒有實現(xiàn),但是為后來的計算機(jī)發(fā)展提供了很大的啟發(fā)。據(jù)說萊布尼茨看了中國的易經(jīng)八卦之后從中發(fā)現(xiàn)了二進(jìn)制,并認(rèn)為以后的計算機(jī)可能會采取二進(jìn)制來實現(xiàn)。
19世紀(jì)早期的英國科學(xué)家巴貝奇發(fā)明了差分機(jī),差分機(jī)可以進(jìn)行一些非常復(fù)雜的數(shù)學(xué)運算,如多項式計算、求解三角函數(shù)等。后來他又設(shè)計出了分析機(jī),但是由于分析機(jī)過于復(fù)雜,在當(dāng)時并沒有制造出來。雖然分析機(jī)沒有造出來,但是它的意義卻是非常巨大的。它的內(nèi)部有存儲部分,有碾磨(相當(dāng)于現(xiàn)在的CPU),還有輸入輸出部分,已經(jīng)可以看到現(xiàn)代計算機(jī)的影子了。而且巴貝奇是第一個意識到計算機(jī)是需要編程的人,在此之前人們一直覺得計算機(jī)如果造出來了,它就可以做任何它能做的事情,并不需要人類為它編程,當(dāng)然之前的人也意識不到編程是什么意思。英國著名詩人拜倫的女兒Ada,自幼對數(shù)學(xué)興趣濃厚,與科學(xué)家交往甚密。后來在其它人的介紹下認(rèn)識了巴貝奇,兩人很快就成為了亦師亦友的關(guān)系。雖然分析機(jī)并沒有造出來,但是Ada還是為分析機(jī)寫了很多程序,所以被后世稱為歷史上第一個程序員。估計絕大多數(shù)人都想不到世界上第一個程序員竟然是位女程序員。后來美國國防部設(shè)計了一種計算機(jī)語言,用的就是Ada的名字來命名的。
然后計算機(jī)從機(jī)械時代到了機(jī)電時代,很快又到了電子時代。1946年2月14日,被認(rèn)為是世界上第一臺電子計算機(jī)的ENIAC誕生了,之后計算機(jī)的發(fā)展就走上了快車道,從電子管到晶體管到集成電路到大規(guī)模集成電路,一直發(fā)展至今。這一段歷史比較清晰,網(wǎng)上的資料也很多,而且這段歷史中計算機(jī)的邏輯結(jié)構(gòu)并沒有發(fā)生多大的變化,所以我們就不展開細(xì)說了。
1.3 計算機(jī)的二元結(jié)構(gòu)
計算機(jī)是由硬件和軟件組成的,就像人是由肉體和靈魂組成的一樣。計算機(jī)的各種硬件就像是人的大腦、心肝脾肺腎、骨骼、皮膚一樣,支撐著人活著。但是人要是只有肉體沒有靈魂,那就是植物人,電腦要是只有硬件沒有軟件,那就是一堆金屬和塑料,沒有用處。下面兩章我們分別講一下計算機(jī)的硬件體系結(jié)構(gòu)和軟件體系結(jié)構(gòu)。
二、計算機(jī)硬件體系結(jié)構(gòu)
我們按照從簡單到復(fù)雜、從抽象到具體的過程來講一講計算機(jī)的硬件體系結(jié)構(gòu)。
2.1 圖靈機(jī)模型
什么是圖靈機(jī),我們?yōu)槭裁匆v圖靈機(jī)?圖靈機(jī)是計算機(jī)的數(shù)學(xué)模型,我們在這里講圖靈機(jī)并不是為了學(xué)習(xí)圖靈機(jī)本身,圖靈機(jī)的理論還是很復(fù)雜的。我們這里講圖靈機(jī)就是為了理解一下計算機(jī)的運行模型,明白CPU的運行是線性的。我們先來看一下圖靈機(jī)的定義,圖靈機(jī)是英國數(shù)學(xué)家阿蘭·圖靈于1936年提出的一種抽象的計算機(jī)模型,即將人們使用紙筆進(jìn)行數(shù)學(xué)運算的過程進(jìn)行抽象,由一個虛擬的機(jī)器替代人類進(jìn)行數(shù)學(xué)運算。它有一條無限長的紙帶,紙帶分成了一個一個的小方格,每個方格有不同的內(nèi)容。有一個機(jī)器頭在紙帶上移來移去。機(jī)器頭有一組內(nèi)部狀態(tài),還有一些固定的程序。在每個時刻,機(jī)器頭都要從當(dāng)前紙帶上讀入一個方格信息,然后結(jié)合自己的內(nèi)部狀態(tài)查找程序表,根據(jù)程序把信息輸出到紙帶方格上,并轉(zhuǎn)換自己的內(nèi)部狀態(tài),然后進(jìn)行移動。我們可以看出圖靈機(jī)的定義還是很簡單的,圖靈機(jī)的運行模式和我們現(xiàn)在的CPU運行模式還是很像的,我們下面畫一個圖靈機(jī)的運行模型。
從圖中我們可以看到圖靈機(jī)模型確實非常簡單,有一個讀寫磁頭,磁頭有自己的內(nèi)部狀態(tài),磁頭根據(jù)自己的內(nèi)部狀態(tài)會讀或者寫當(dāng)前方格里面的內(nèi)容,然后相應(yīng)地改變自己的狀態(tài),然后向左或者向右移動一格或者若干格繼續(xù)執(zhí)行。圖靈機(jī)本身的理論非常復(fù)雜,想學(xué)習(xí)的同學(xué)可以去搜索一下或者查閱相關(guān)的書籍。我們在這里想要說的就一點,圖靈機(jī)的運行是線性的,線性的意思不是說它是單向直線性的,而是說它只能在一條線上運行,而且所有運行的點按時間記錄排序是線性的。
2.2 馮諾依曼結(jié)構(gòu)
馮諾依曼結(jié)構(gòu)是計算機(jī)的物理模型,是計算機(jī)能夠制造出來的關(guān)鍵。馮諾依曼結(jié)構(gòu)由三部分組成:一是計算機(jī)硬件實現(xiàn)上采用二進(jìn)制;二是存儲程序設(shè)計,就是把計算機(jī)程序放到存儲器中,關(guān)于這一部分的論述就參看《深入理解編譯體系》的第一章;三是計算機(jī)由控制器、運算器、存儲器、輸入設(shè)備、輸出設(shè)備五個部分組成。控制器是整個計算機(jī)的神經(jīng)中樞,控制著整個計算機(jī)的運轉(zhuǎn)??刂破鲝拇鎯ζ髦腥≈噶?,解析指令,然后根據(jù)指令的內(nèi)容讓運算器進(jìn)行相應(yīng)的運算或者向其它部件發(fā)出一些命令。運算器是負(fù)責(zé)進(jìn)行數(shù)學(xué)運算和邏輯運算的部件,數(shù)學(xué)運算包括加減乘除移位比較等運算,邏輯運算包括與、或、非、異或等運算。存儲器是存儲程序和數(shù)據(jù)的地方。輸入設(shè)備和輸出設(shè)備是負(fù)責(zé)和人交互的設(shè)備,人們通過輸入設(shè)備向計算機(jī)輸入命令和數(shù)據(jù),通過輸出設(shè)備得到計算機(jī)運算出來的結(jié)果。下面我們畫一張馮諾依曼結(jié)構(gòu)的圖。
可以看到馮諾依曼結(jié)構(gòu)比圖靈機(jī)模型復(fù)雜了不少,但是總體上還是很簡單的。有了馮諾依曼結(jié)構(gòu),計算機(jī)就有了被造出來的物理模型,我們也可以從馮諾依曼結(jié)構(gòu)中更好地去理解計算機(jī)的邏輯結(jié)構(gòu)。
2.3 現(xiàn)代計算機(jī)結(jié)構(gòu)
其實并沒有現(xiàn)代計算機(jī)結(jié)構(gòu)這個術(shù)語,現(xiàn)代計算機(jī)結(jié)構(gòu)是我把馮諾依曼結(jié)構(gòu)再具體化一下,把具體計算機(jī)結(jié)構(gòu)再抽象化一下總結(jié)出來的,可以讓大家更方便更深入地理解計算機(jī)硬件體系結(jié)構(gòu)?,F(xiàn)代計算機(jī)和馮諾依曼結(jié)構(gòu)最主要的區(qū)別是把控制器和運算器合二為一稱作CPU,把存儲器一分為二,分為內(nèi)存和外存。我們來畫一下現(xiàn)代計算機(jī)結(jié)構(gòu)的圖。
現(xiàn)代計算機(jī)的具體體系結(jié)構(gòu)非常復(fù)雜,我只是撿其中比較關(guān)鍵的畫了出來,很多細(xì)節(jié)沒有畫,如總線、南橋、北橋、各種控制器等,上圖中也有很多連線沒有畫。計算機(jī)運行的時候先從外存中加載程序到內(nèi)存,然后CPU不斷地執(zhí)行內(nèi)存中的指令、讀寫內(nèi)存數(shù)據(jù),CPU也會使內(nèi)存繼續(xù)從外存中讀取數(shù)據(jù)或者把內(nèi)存的數(shù)據(jù)更新到外存。CPU通過IO端口或者內(nèi)存映射IO來控制外設(shè)獲取外設(shè)的狀態(tài)或者數(shù)據(jù),外設(shè)通過中斷控制器(APIC)向CPU通知報告一些事情。計算機(jī)就是這樣不斷運行的。
推薦閱讀:
想要深入學(xué)習(xí)計算機(jī)體系結(jié)構(gòu)的話,推薦閱讀《Structured Computer Organization》《Computer Architecture A Quantitative Approach》《Computer Organization and Design》《Computer Systems - A Programmer’s Perspective》《Code The Hidden Language of Computer Hardware and Software》《Computer Organization and Architecture Designing for Performance》
想要學(xué)習(xí)CPU設(shè)計運行原理的話,推薦閱讀《Modern Processor Design》《Microprocessor Architecture》《Processor Microarchitecture An Implementation Perspective》《Chip Multiprocessor Architecture Techniques to Improve Throughput and Latency》《CPU自制入門》《自己動手寫CPU》《大話處理器》。
想要了解具體CPU的運行原理的話可以閱讀CPU廠商的CPU手冊,x86 CPU:《Intel 64 and IA-32 Architectures Software Developer’s Manual》,一共4卷10冊,總共4800多頁,下載地址:https://software.intel.com/en-us/articles/intel-sdm。ARM:《Arm Architecture Reference Manual for A-profile architecture》,只有一個整體本,不分卷分冊,總共11000多頁,下載地址:https://developer.arm.com/Architectures/A-Profile%20Architecture。RISC-V:《The RISC-V Instruction Set Manual Volume I User-Level ISA》《The RISC-V Instruction Set Manual Volume I I Priv ileged Architecture》,分別230,250多頁,下載地址:https://riscv.org/technical/specifications。
三、計算機(jī)軟件體系結(jié)構(gòu)
從上面我們知道了硬件的整體結(jié)構(gòu)和運行情況,下面我們來說一說計算機(jī)的軟件體系結(jié)構(gòu)。計算機(jī)軟件整體上分為系統(tǒng)軟件和應(yīng)用軟件,系統(tǒng)軟件是面向硬件和面向程序員的軟件,應(yīng)用軟件是面向普通用戶的軟件。
3.1 系統(tǒng)軟件
最重要的系統(tǒng)軟件是操作系統(tǒng),操作系統(tǒng)是管理所有硬件并為進(jìn)程提供運行環(huán)境的軟件,所有的應(yīng)用程序都要運行在操作系統(tǒng)之上,操作系統(tǒng)為應(yīng)用程序提供服務(wù),并管理所有的應(yīng)用程序。關(guān)于操作系統(tǒng)的具體情況,請看第四章和第五章。
在操作系統(tǒng)啟動之前還有兩個軟件,它們是Boot Firmware 和 BootLoader,Boot Firmware的存在有一個原因、兩個作用:一個原因是為了克服計算機(jī)啟動時雞生蛋、蛋生雞的矛盾,按照馮諾依曼模型,計算機(jī)啟動時要從內(nèi)存讀取程序運行程序,而計算機(jī)啟動時內(nèi)存是空的啥都沒有,要想讓內(nèi)存有程序就必須要從外存中加載程序,而從外存中加載程序的指令也是程序,這個程序也要先加載到內(nèi)存,怎么辦呢,我們提前寫好一段程序,把它固化到ROM中去,ROM是掉電不會丟失內(nèi)容的,再把這個ROM配置到特定的物理內(nèi)存地址空間中,具體地址是什么要看CPU廠商了。CPU啟動時會從特定的內(nèi)存地址運行,也就是這個ROM所在地址,這樣CPU就有程序可以執(zhí)行了。Boot Firmware的兩個作用分別是初始化硬件檢測硬件和加載操作系統(tǒng)為操作系統(tǒng)提供一些基本的硬件信息。后來為了靈活性,Boot Firmware并不是直接加載的操作系統(tǒng),而是先加載BootLoader再由BooLoader加載的操作系統(tǒng)。BootLoader的存在一是可以很方便配置一些信息如OS啟動參數(shù),二是支持多操作系統(tǒng)啟動。桌面計算機(jī)常見的Boot Firmware是BIOS和UEFI,BIOS是PC最初的Boot Firmware,由于推出的時間比較早,所以存在很多問題,后來Intel又重新設(shè)計開發(fā)了UEFI,UEFI相比BIOS由很多的優(yōu)點?,F(xiàn)在基本上大部分桌面計算機(jī)都已經(jīng)轉(zhuǎn)向了UEFI。比較常見的Boot Loader如LILO、GRUB,現(xiàn)在桌面版Linux用的基本都是GRUB。
嵌入式系統(tǒng)的概念和這個不太一樣,嵌入式系統(tǒng)最先啟動的兩個軟件叫做Boot ROM和BootLoader,Boot ROM存在的原因和Boot Firmware存在的原因是一樣的,但是Boot ROM并不具有Boot Firmware的功能,Boot ROM是比較輕的,相當(dāng)于是UEFI/PI 中的SEC階段,Boot Firmware中的其它功能被轉(zhuǎn)移到BootLoader中來做,Boot ROM一般是由CPU廠商來開發(fā)的,不開源。BootLoader負(fù)責(zé)硬件初始化并直接加載啟動操作系統(tǒng)。造成桌面計算機(jī)和嵌入式系統(tǒng)的這種差異的原因是兩者的運行和使用環(huán)境大不相同造成的。
作為最基礎(chǔ)的三個系統(tǒng)軟件,Boot Firmware、BootLoader、操作系統(tǒng),前兩者很少有人熟悉,甚至很多人根本就沒聽說過,是因為它們啟動過去之后基本就不再起作用了。除此之外還有一套很重要的系統(tǒng)軟件,它是編譯工具鏈,包括預(yù)處理器、編譯器、匯編器、鏈接器,所有的軟件要想從源碼變成二進(jìn)制程序都需要它們來處理,想要具體了解它們的情況請參看《深入理解編譯系統(tǒng)》。除此之外還有一些系統(tǒng)查看、配置、維護(hù)工具也算是系統(tǒng)軟件,如ps、top、sysctl等。
推薦閱讀:
想要學(xué)習(xí)操作系統(tǒng)理論的話,推薦閱讀《Modern Operating Systems》《Operating System Concepts》《Operating Systems Design and Implementation》《Operating Systems Three Easy Pieces》《Operating Systems In Depth》《Operating Systems Internals and Design Principles》《Operating Systems A Concept-Based Approach》《現(xiàn)代操作系統(tǒng)》這本是陳海波/夏虞斌著,和第一本的漢譯版重名,并不是同一本書。
想要學(xué)習(xí)Windows操作系統(tǒng)的話,推薦閱讀《Windows Internals 7th Part 1》和《Windows Internals 7th Part 2》
想要學(xué)習(xí)Mac OS操作系統(tǒng)的話,推薦閱讀《Mac OS X and iOS Internals》和《Mac OS X Internals A Systems Approach》
3.2 應(yīng)用軟件
應(yīng)用軟件就比較好理解了,就是那些面向普通用戶實現(xiàn)某些特定需求的軟件,如 上網(wǎng)-瀏覽器,聽歌-千千靜聽,看視頻-暴風(fēng)影音,追劇-愛奇藝,社交-微信,購物-淘寶,刷視頻-抖音。所有應(yīng)用軟件都運行在操作系統(tǒng)之上,享受操作系統(tǒng)的服務(wù),并接受操作系統(tǒng)的管理。
四、操作系統(tǒng)組成結(jié)構(gòu)
我們經(jīng)常說操作系統(tǒng),那么究竟什么是操作系統(tǒng)呢,我們先來從操作系統(tǒng)的構(gòu)成成分的角度來講一講。操作系統(tǒng)是由三部分構(gòu)成的,其中最重要的是內(nèi)核部分,但是內(nèi)核并不是操作系統(tǒng)的全部,除了內(nèi)核外,OS庫和OS進(jìn)程也是操作系統(tǒng)的一部分。OS庫是運行在用戶空間進(jìn)程中的共享庫,雖然它是運行在用戶空間,雖然它只是共享庫,但是它是操作系統(tǒng)的一部分,因為它參與實現(xiàn)了操作系統(tǒng)的一部分功能。OS進(jìn)程雖然是運行在用戶空間的進(jìn)程,但是它并不屬于應(yīng)用程序,因為它是實現(xiàn)操作系統(tǒng)功能必不可少的一部分。
4.1 內(nèi)核
內(nèi)核是操作系統(tǒng)最重要的部分,是操作系統(tǒng)的核心,它運行在內(nèi)核空間,運行在CPU特權(quán)模式,直接與硬件打交道,并直接管理著進(jìn)程的運行。內(nèi)核可以分為宏內(nèi)核與微內(nèi)核,宏內(nèi)核就是傳統(tǒng)的內(nèi)核方式,所有的內(nèi)核功能都放在內(nèi)核空間里。微內(nèi)核是把一些最基本的無法移出內(nèi)核的功能才放在內(nèi)核里,其它能放到用戶空間的功能全都放到用戶空間進(jìn)程里,叫做微服務(wù),應(yīng)用進(jìn)程通過IPC與微服務(wù)溝通,微服務(wù)與微內(nèi)核一起構(gòu)成一個完成的內(nèi)核。
微內(nèi)核辯論:
我對微內(nèi)核的態(tài)度是和Linus是一樣的,下面的話是節(jié)選自Linus寫的書《Just For Fun》。
微內(nèi)核的理論依據(jù)是,操作系統(tǒng)是非常復(fù)雜的,所以要通過模式化來減少復(fù)雜性。微內(nèi)核方法的原則,即核心的核心,是盡量減少功能。它的主要功能是傳播。電腦所提供的一系列不同的服務(wù)都是通過微內(nèi)核的傳播渠道實現(xiàn)的。因此,應(yīng)盡量分割問題的空間,使其不再復(fù)雜。我認(rèn)為這種做法很愚蠢。是的,每一個單獨的部分是簡單的,但是相互作用的多種功能如果放在一起就要復(fù)雜得多 ,而 Linux 就是后者的情況。想一想自己的大腦。每一個單獨的部分都很簡單,但是各部分的相互作用構(gòu)成了一個復(fù)雜的系統(tǒng)。這是一個整體比個別更大的問題。拿一個問題來說,如果你簡單地將問題一分為二,說半個問題要容易一半,那么你就忽略了一個事實,即:你必須要考慮到兩個半個之間的聯(lián)系所帶來的復(fù)雜性。微內(nèi)核的理論是,如果把核分為五十份,那么每一份都只有五十分之一的復(fù)雜性。但是每個人都忽視了一個事實,即各部分之間的聯(lián)系事實上比源系統(tǒng)更加復(fù)雜,而且那些個別部分也不是那么簡單。這是我對微內(nèi)核最重要的反駁:你想實現(xiàn)的簡單化是錯誤的簡單化。
上面是Linus的分析,我是非常贊同的,內(nèi)核的復(fù)雜是內(nèi)核的固有屬性,是它內(nèi)在邏輯的復(fù)雜,你把它人為的劃分到不同的用戶空間進(jìn)程,并沒有減少它內(nèi)在的邏輯復(fù)雜性。把一個事物模塊化能減少它的復(fù)雜性,但是模塊化不是說非得要在形式上把它們分割到不同的進(jìn)程,在邏輯上把它們分割開來就可以了。比如說有一個進(jìn)程非常復(fù)雜,你把它弄成一坨不分模塊是不對的,但是模塊化的形式可以是把它分割成一個exe和n個so就可以了,不一定非要把它做成n+1個進(jìn)程。n+1個模塊無論是在進(jìn)程內(nèi)交互,還是在進(jìn)程間交互,其本身的復(fù)雜性并沒有減少,進(jìn)程間通信還降低了效率。
微內(nèi)核還有一個經(jīng)常宣傳的優(yōu)點是如果某個微服務(wù)出了問題,只重啟這個微服務(wù)就可以了,不用重啟整個內(nèi)核。但是這個優(yōu)點是禁不起推敲的,以我在安卓系統(tǒng)上的工作經(jīng)驗為例,如果某個重要的JAVA進(jìn)程崩潰重啟了比如SystemServer,就會導(dǎo)致很多Java進(jìn)程包括所有的APK進(jìn)程都會重啟,雖然內(nèi)核沒有重啟,但是在用戶看來還是整個系統(tǒng)都重啟了。所以如果某個微服務(wù)重啟了,一定會導(dǎo)致所有的應(yīng)用進(jìn)程重啟的,在用戶看來還是整個系統(tǒng)重啟了,也許你會說微內(nèi)核本身并沒有重啟,所以整個重啟時間減少了,但是這點時間減少并沒有多少意義。而微內(nèi)核帶來的整個系統(tǒng)性能的大幅度下降這個問題,則是無法容忍和無法克服的。
我發(fā)現(xiàn)很多嵌入式系統(tǒng)使用的都是微內(nèi)核。因為嵌入式系統(tǒng)是一個相對封閉的系統(tǒng),不會有經(jīng)常下載新程序、突然運行很多進(jìn)程的情況,所以嵌入式系統(tǒng)對性能的需求是穩(wěn)定的。所以微內(nèi)核只要在測試中能滿足嵌入式系統(tǒng)的性能需求,問題就不大。通用操作系統(tǒng)包括手機(jī)系統(tǒng)、桌面系統(tǒng)、服務(wù)器系統(tǒng),都有面臨負(fù)載突然暴增的情況,所以對性能的要求非常高。
目前所有流行的通用操作系統(tǒng)內(nèi)核都是宏內(nèi)核,有些宣稱自己是微內(nèi)核或者混合內(nèi)核的,本質(zhì)上還是宏內(nèi)核?!禡ac OS X Internals A Systems Approach》6.2章節(jié)明確說XNU不是微內(nèi)核,是宏內(nèi)核,《Mac OS X and iOS Internals》第8章Hybrid Kernels這一節(jié)說,Windows、MacOS雖然是混合內(nèi)核,但是實際上還是宏內(nèi)核。
4.2 OS庫
有些運行在用戶空間的動態(tài)庫,是屬于操作系統(tǒng)的一部分,這些庫雖然是庫,但是并不是由應(yīng)用程序開發(fā)者開發(fā),而是由操作系統(tǒng)廠商開發(fā),因為它們是構(gòu)成操作系統(tǒng)功能的一部分。在Linux上常見的OS庫有l(wèi)ibc.so、ld-linux-x86-64.so、libm.so、libpthread.so、libdl.so、librt.so、libcrypt.so、libpam.so、libX11.so等。Linux上的OS庫是非常多的,上面只是隨便舉幾個例子,下面我們對其中最重要的幾個進(jìn)行一下分析。
libc.so,libc(C Library)的二進(jìn)制動態(tài)庫形式,它的源碼實現(xiàn)有很多,Linux發(fā)行版一般用的是glibc,安卓上的libc的實現(xiàn)叫做bionic。libc不僅生成libc.so,還有l(wèi)ibpthread.so、ld-linux-x86-64.so等很多庫都是libc生成的。libc.so里面不僅有C標(biāo)準(zhǔn)庫的實現(xiàn),還有對系統(tǒng)調(diào)用的封裝,所以libc.so不是一個普通的庫,它是內(nèi)核的對外接口庫,是非常重要的,是進(jìn)程運行必不可少的。你cat 任何一個進(jìn)程的 /proc/pid/maps 幾乎一定會看到libc.so,如果看不到,那是因為有些進(jìn)程是把libc靜態(tài)鏈接到自身了,進(jìn)程里面還是包含libc的。
ld-linux-x86-64.so,是Linux系統(tǒng)的加載器,負(fù)載在進(jìn)程啟動時把進(jìn)程所依賴的所有動態(tài)庫都加載到內(nèi)存并進(jìn)行一些重定位工作。沒有了ld-linux-x86-64.so,幾乎所有的應(yīng)用進(jìn)程都無法啟動運行。
libpthread.so,Linux的多線程實現(xiàn)庫,想要使用系統(tǒng)的多線程功能的進(jìn)程必須要調(diào)用這個so才行。
4.3 OS進(jìn)程
并不是所有的操作系統(tǒng)功能都放進(jìn)了內(nèi)核里,還有很多功能是放在了用戶進(jìn)程里來實現(xiàn)的,我們把這些進(jìn)程叫做OS進(jìn)程。我總結(jié)了一些常見的放在用戶空間的操作系統(tǒng)功能,它們是 init system、package system、window system。這些都被叫做某某系統(tǒng),可見它們并不是簡單的一個進(jìn)程而已,它們一般是由一個進(jìn)程加上一些配置文件,有的還提供一些so,它們有著自己的邏輯體系,下面我們來一一講解一下。
Init system,是操作系統(tǒng)啟動的第一個用戶空間進(jìn)程,它負(fù)責(zé)把整個用戶空間給啟動起來,啟動系統(tǒng)所有的守護(hù)進(jìn)程,設(shè)置一些系統(tǒng)配置,在系統(tǒng)運行的過程中監(jiān)管著整個系統(tǒng),系統(tǒng)的關(guān)機(jī)也由它負(fù)責(zé)。最早的init system 叫 sysv init,它的實現(xiàn)比較簡單直接方便,大量使用腳本。后來sysv init 變成了系統(tǒng)啟動速度慢的最大瓶頸,一是因為腳本的運行比較慢,二是因為它是單線程的,沒能發(fā)揮出多核的優(yōu)勢。后面就出現(xiàn)了兩個init system,分別是upstart 和 systemd 來解決sysv init 的問題,現(xiàn)在大部分linux發(fā)行版都把init system 換成了systemd。
Package system,一個系統(tǒng)上有那么多的軟件,該如何安裝、如何卸載、如何管理,安裝包該采取什么格式,這便是package system要做的工作。目前Linux上有兩個比較流行的package system,一個是redhat 推出的rpm,一個是debian推出的dpkg。
Window system 也叫做Graphics system,也就是一個操作系統(tǒng)的圖形界面該如何管理,這是一個非常復(fù)雜的系統(tǒng),牽涉面非常廣,為什么是Android呢,因為我在手機(jī)廠商工作的時候做過這方面的工作,相對比較熟悉,對Linux的圖形系統(tǒng)不太熟悉。
除了上面三個很大的系統(tǒng)之外,還有一些GUI程序,看起來像是應(yīng)用程序,但是實際上應(yīng)該劃到操作系統(tǒng)的內(nèi)容里面,比如桌面、文件管理器、設(shè)置等程序,因為它們是和操作系統(tǒng)緊密相關(guān)的,而且一般也是由操作系統(tǒng)廠商來開發(fā)和維護(hù)的。
五、操作系統(tǒng)本質(zhì)解析
前面我們對操作系統(tǒng)的組成結(jié)構(gòu)進(jìn)行了分析,下面我們從操作系統(tǒng)的功能作用的角度再對操作系統(tǒng)進(jìn)行具體的分析。我們先來思考一個問題,什么是操作系統(tǒng),為什么要有操作系統(tǒng)?我們通過對操作系統(tǒng)發(fā)展歷史的研究以及對Linux內(nèi)核實現(xiàn)的深入研究發(fā)現(xiàn),操作系統(tǒng)的存在就是為了一個目的,就是為了運行程序,如果再加個形容詞的話,那就是多快好省地運行程序。為了實現(xiàn)這個目的,操作系統(tǒng)提供了兩個作用:1.操作系統(tǒng)是一個更加高級的抽象計算機(jī),2.操作系統(tǒng)是計算機(jī)資源管理器。下面我們對一個目的、兩個作用展開討論。
5.1 操作系統(tǒng)的目的
操作系統(tǒng)存在的目的就是為了運行程序。我們還可以用反證法來論證這個結(jié)論,假設(shè)操作系統(tǒng)不能用來運行程序,那么操作系統(tǒng)要它還有什么用呢。所以操作系統(tǒng)存在的目的就是為了運行程序,為了多快好省地運行程序,多就是多任務(wù),快就是效率高,好就是安全穩(wěn)定,省就是節(jié)省資源,為了實現(xiàn)這個目的,操作系統(tǒng)做了非常大的努力。
既然是為了運行程序,那么我們要問的第一個問題就是程序是怎么來的呢。首先程序是用計算機(jī)編程語言編寫的。編寫程序的工具是什么呢,是文本編輯器。編寫的原則是什么呢,隨便怎么寫都可以嗎,不是的,首先要符合所使用語言的語法才行。其次我們對程序還有幾個要求,其中首先最重要的要求就是正確性,程序運行結(jié)果不正確可不行,除了編程時我們小心翼翼盡量保證程序邏輯正確外,我們在運行的時候發(fā)現(xiàn)程序不正確時還要用調(diào)試工具GDB來調(diào)試程序,找到程序的錯誤改正它。對于程序的內(nèi)存錯誤,我們還可以使用asan、malloc-debug、valgrind等工具來排查錯誤。再者我們寫的程序還要簡潔清晰、可讀性強(qiáng)、可維護(hù)性強(qiáng),為了達(dá)到這個目的,我們要學(xué)習(xí)很多編程的藝術(shù),在此給大家推薦幾本書:《Agile Software Development》《Clean Code》《The Clean Coder》《Clean Architecture》《Code Complete》《Design Patterns》《Refactoring Improving the Design of Existing Code》。其中大家在很多博客上經(jīng)??吹降囊恍┚幊淘瓌t如開閉原則、單一責(zé)任原則、依賴倒置原則等都是出自第一本書,漢譯書名叫《敏捷軟件開發(fā)》。再者我們寫的程序還要具有高效性,程序效率低運行慢可不行,那么怎么讓我們寫的程序比較高效呢,為此我們要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法,只有把數(shù)據(jù)結(jié)構(gòu)與算法學(xué)透了,我們才能把我們學(xué)到的方法和我們的需求結(jié)合起來,寫出來運行又快占用空間又小的程序。為此我向大家推薦幾本書:《Introduction to Algorithms》《Algorithm Design and Applications》《Algorithms in a Nutshell》《Data Structures and Algorithms in Java》《Algorithms》《An Introduction to the Analysis of Algorithms》。如果是已經(jīng)寫好的程序嫌它運行慢應(yīng)該怎么辦呢,我們有性能剖析工具gprof,它能幫你找到熱點代碼,然后你就可以進(jìn)行定向優(yōu)化,必要時還可以使用匯編語言實現(xiàn)一些函數(shù)來提高效率。
當(dāng)我們把源代碼都寫好了之后,程序就可以運行了嗎,不行,CPU不認(rèn)識源代碼,只認(rèn)識二進(jìn)制程序,所以我們還需要把源代碼編譯、鏈接成二進(jìn)制程序才行。二進(jìn)制程序有沒有格式呢,隨便怎么生成都行嗎,不行,不同的操作系統(tǒng)都有自己特定的二進(jìn)制程序格式。Linux使用的二進(jìn)制程序格式叫做ELF格式,ELF是一個總體格式,在不同的操作系統(tǒng)上、不同的CPU架構(gòu)上又有一些具體細(xì)化的要求,如都有哪些段,函數(shù)怎么傳遞參數(shù)等,這些統(tǒng)稱為ABI,應(yīng)用程序二進(jìn)制接口。源碼生成的二進(jìn)制程序可以分為exe主程序和so動態(tài)庫程序,主程序可以直接執(zhí)行,庫程序不能直接執(zhí)行,只能在別人的進(jìn)程里被調(diào)用執(zhí)行。程序運行起來就是進(jìn)程,一個進(jìn)程由一個exe主程序和n個so庫程序構(gòu)成。
還有一個概念叫做IDE,集成開發(fā)環(huán)境,它是一個圖形界面程序,里面集成了文件編輯器、調(diào)試器、編譯器、鏈接器、Build工具等,可以在一個程序里完成一系列開發(fā)操作。
5.2 操作系統(tǒng)的作用之一
操作系統(tǒng)為了運行程序提供了哪些作用呢,第一個就是操作系統(tǒng)是一個更加高級的抽象計算機(jī)。怎么理解這句話呢,我們從計算機(jī)發(fā)展的歷史來講解。最開始的時候是沒有操作系統(tǒng)的,只有應(yīng)用程序,應(yīng)用程序的開發(fā)要直接面向硬件開發(fā),因為沒有人給你提供API。比如說你要讀寫一個文件,你該怎么辦,要是擱現(xiàn)在那是很簡單的,你只需要open(file path),read(fd),write(fd)就可以了。但是在當(dāng)時讀寫卻是非常復(fù)雜的,你需要了解磁盤的型號,知道磁盤的端口,知道磁盤的各個技術(shù)參數(shù)如磁盤有多少個盤面柱面扇區(qū),你要自己編程管理每一個扇區(qū),記錄哪一個扇區(qū)用過了哪一個扇區(qū)沒用過,想想都頭疼,都想放棄?,F(xiàn)在好了,現(xiàn)在有操作系統(tǒng)幫你做這些事情,你只需要按照操作系統(tǒng)給你的API去做就行了,那是十分的方便啊。操作系統(tǒng)向應(yīng)用程序提供的功能,從底層實現(xiàn)的角度來看叫做系統(tǒng)調(diào)用,從上層應(yīng)用的角度來看叫做API,系統(tǒng)調(diào)用和API看起來很像又不太一樣,但是它倆又有很強(qiáng)的關(guān)聯(lián)。
5.3 操作系統(tǒng)的作用之二
操作系統(tǒng)的第一個作用是從單個進(jìn)程的角度來看的,操作系統(tǒng)是一個更加高級的抽象計算機(jī)。現(xiàn)在我們從多個進(jìn)程的角度來看,又發(fā)現(xiàn)操作系統(tǒng)其實是個計算機(jī)資源管理器。這和操作系統(tǒng)的標(biāo)準(zhǔn)定義又很契合,我們來看一下操作系統(tǒng)的標(biāo)準(zhǔn)定義:操作系統(tǒng)是管理計算機(jī)硬件與軟件資源的計算機(jī)程序。操作系統(tǒng)需要處理如管理與配置內(nèi)存、決定系統(tǒng)資源供需的優(yōu)先次序、控制輸入設(shè)備與輸出設(shè)備、操作網(wǎng)絡(luò)與管理文件系統(tǒng)等基本事務(wù)。操作系統(tǒng)也提供一個讓用戶與系統(tǒng)交互的操作界面。
既然操作系統(tǒng)是計算機(jī)資源管理器,那么我們先來看一看計算機(jī)都有哪些資源呢?從第二章我們可以看出,計算機(jī)最主要的資源有CPU、內(nèi)存、外存、外設(shè),因此我們可以很輕易地看出操作系統(tǒng)的四個必要組成部分分別是CPU管理、內(nèi)存管理、外存管理、設(shè)備管理。CPU管理就是CPU時間管理就是進(jìn)程調(diào)度。內(nèi)存管理是對內(nèi)存資源進(jìn)行管理,包括物理內(nèi)存的管理和虛擬內(nèi)存的管理。外存管理包括文件系統(tǒng)和磁盤驅(qū)動兩部分。設(shè)備管理是最復(fù)雜的,一般都是由內(nèi)核提供基礎(chǔ)代碼和驅(qū)動模型,由各個硬件廠商具體去寫自家設(shè)備的驅(qū)動程序,系統(tǒng)還會制定用戶空間接口,提供一些基礎(chǔ)操作庫。由于Linux支持的設(shè)備眾多,因此設(shè)備驅(qū)動代碼是Linux里面代碼最多的部分,占Linux總代碼的比例高達(dá)60%多。
操作系統(tǒng)管理計算機(jī)資源總體上有四種模式,分別是:1時間分割管理,2空間分割管理,3獨占性管理,4直接管理。我們把資源分為共享性資源和非共享性資源。共享不共享是相對于進(jìn)程來說的,有些資源直接對整個系統(tǒng)起作用,對進(jìn)程不可用,我們把系統(tǒng)對這種資源的管理方法叫做直接管理,例如中斷控制器。對于共享性資源,我們要根據(jù)資源自身的特點采取相應(yīng)的管理方式。資源的特點包括時間分割相似性和空間分割相似性。時間分割相似性是指在一個較少的時間片上資源仍然是可用的??臻g分割相似性是指把資源分割成若干份,每一個仍然能達(dá)到資源本身的作用。對于具有時間分割相似性的資源我們采取時間分割管理,對于具有空間分割相似性的資源我們采取空間分割管理,如果兩者都不具有我們采取獨占性管理。
CPU管理:
對CPU應(yīng)該怎么管理呢,我們來思考一下。我們能不能采用空間分割管理呢?試一下,如果用空間分割管理,那么就是把一個CPU分割為n個部分,每個部分都是一個獨立的執(zhí)行單元,n個進(jìn)程各占一個各運行各的,好像也行,但是根據(jù)我們在第二章所學(xué)的知識,CPU做不到啊。如果用時間分割管理呢,把時間分成一片一片的,輪流分給每個進(jìn)程來使用,由于CPU是一條指令一條指令地執(zhí)行,不同進(jìn)程之間的指令是沒有依賴關(guān)系的,所以是可以的。所以我們對CPU采取的管理方式是時間分割管理。對CPU進(jìn)行時間分割管理就是進(jìn)程調(diào)度。
進(jìn)程調(diào)度需要統(tǒng)計進(jìn)程的運行時間,被動調(diào)度需要有定時器的支持,文件系統(tǒng)需要給文件打上時間戳,用戶空間也有查看時間、修改時間、設(shè)置定時器的需求。
內(nèi)存管理:
我們再來看一下對內(nèi)存應(yīng)該使用什么管理方式。內(nèi)存能不能進(jìn)行時間分割管理呢?能,把時間分成一片一片的,每個時間片就只有一個進(jìn)程就能獨享整個內(nèi)存。顯然這么做很不利于充分使用內(nèi)存,太浪費了,違背了多快好省地運行進(jìn)程的原則。那么能不能對內(nèi)存進(jìn)行空間分割管理呢?能,每個進(jìn)程占用一小塊內(nèi)存進(jìn)行運行,這樣能充分利用整個內(nèi)存。這么做有沒有什么缺點呢?有,內(nèi)核和各個進(jìn)程都在物理內(nèi)存里,大家都可以相互訪問甚至破壞別人的內(nèi)存,顯然是不安全的。對此有什么辦法呢,最先想到的也是最直觀的方法就是分段機(jī)制,修改CPU的運行原理,實現(xiàn)分段機(jī)制,內(nèi)核、每個進(jìn)程各自運行在各自的段里面。由于是在CPU硬件上實現(xiàn)的限制,誰也無法訪問自己段外面的內(nèi)存,這樣就實現(xiàn)了進(jìn)程隔離,非常安全了。但是這么做有沒有缺點呢?有,物理內(nèi)存本來就少,分完段之后物理空間就更小了,而且還有一個缺點就是程序啟動的時候就要把程序全部加載到內(nèi)存才行,不然運行到?jīng)]有加載的程序就崩潰了。對此有什么解決辦法嗎,最剛開始想的辦法是軟件的,每個程序要自己要寫個overlay manager,程序員要對自己程序的執(zhí)行流程有清晰的認(rèn)識,自己控制何時把哪部分即將會用到的程序加載到內(nèi)存,何時將哪部分暫時不會使用的程序再放回外存,這樣程序就可以使用較少的內(nèi)存也能順利運行了。但是這個做法非常麻煩,對程序員的考驗非常大,要解決這個問題還是得使用硬件機(jī)制才行。于是后來就產(chǎn)生了虛擬內(nèi)存/分頁機(jī)制,每個進(jìn)程都運行在虛擬內(nèi)存上,并且獨占整個虛擬內(nèi)存空間,這樣就實現(xiàn)了進(jìn)程隔離,非常安全,同時進(jìn)程并不立即分配物理內(nèi)存,而是程序在運行的過程中產(chǎn)生page fault 按需調(diào)頁,用到的時候再去分配物理內(nèi)存,這樣就可以節(jié)省物理內(nèi)存。所以Linux對內(nèi)存的管理方式是在形式上每個進(jìn)程都獨占整個虛擬內(nèi)存空間,在實際上進(jìn)程之間對物理內(nèi)存進(jìn)行空間分割管理,而且是延遲分配,用到的才分配,用不到就不分配,又節(jié)省了物理內(nèi)存,分頁機(jī)制真是太完美了。
外存管理:
顯然,外存也是采用空間分割管理的。
外設(shè)管理:
有些設(shè)備比如相機(jī),既不具有時間分割相似性,也不具有空間分割相似性,只能對其進(jìn)行獨占性管理。我們可以來假設(shè)一下,如果對相機(jī)進(jìn)行時間分割管理的話,比如說A進(jìn)程用了0.5秒拍照拍了一半,B進(jìn)程又用了0.5秒拍照拍了一半,然后A進(jìn)程又用了0.5秒把整個照片拍完了,接著B進(jìn)程又用0.5秒把整個照片拍完了,顯然這是不可能的,因為相機(jī)做不到。我們再假設(shè)對相機(jī)進(jìn)行空間分割管理,比如說這個相機(jī)拍照的分辨率是1000×800的,A、B兩個進(jìn)程同時用相機(jī),分別拍出了一個1000×400的照片,這也是不可能的,相機(jī)做不到。所以對相機(jī)只能采取獨占性管理,每個進(jìn)程在使用相機(jī)前都要先申請,使用完后再釋放,使用期間進(jìn)程對相機(jī)是獨占的。
計算機(jī)中除了CPU、內(nèi)存、主板、總線等之外的設(shè)備都叫做外設(shè),內(nèi)核對外設(shè)的管理叫做設(shè)備管理,也是操作系統(tǒng)中非常重要的一塊。外設(shè)的運行需要驅(qū)動程序,內(nèi)核一般會提供總線的驅(qū)動和一些設(shè)備類型的框架代碼,然后由各個硬件廠商去編寫具體的驅(qū)動程序。想學(xué)習(xí)Linux驅(qū)動編程的話,推薦閱讀《Linux Device Drivers》《Essential Linux Device Drivers》《Linux設(shè)備驅(qū)動開發(fā)詳解》。
有些設(shè)備,并不是單單有個驅(qū)動就能獨立運行了,而是與用戶空間庫和進(jìn)程一起構(gòu)成了一個新的系統(tǒng),比如網(wǎng)卡和顯示器。網(wǎng)卡需要網(wǎng)卡驅(qū)動,但是只有網(wǎng)卡驅(qū)動,網(wǎng)卡還是沒有用,網(wǎng)卡與網(wǎng)卡驅(qū)動還有網(wǎng)絡(luò)協(xié)議還有一些相關(guān)的硬件軟件共同構(gòu)成了網(wǎng)絡(luò)系統(tǒng)。再說顯示器,光有個顯示驅(qū)動也是沒有意義的,顯示器只是計算機(jī)圖形系統(tǒng)中的一個組成部分。計算機(jī)圖形系統(tǒng)還包括GPU、渲染庫、窗口系統(tǒng)等很多組件。
中斷機(jī)制:
計算機(jī)中外設(shè)與CPU的交互方式,除了CPU可以控制外設(shè)之外,外設(shè)也可以主動向CPU報告事情,避免了CPU輪詢外設(shè)的低效行為,這種方式就叫做中斷。中斷除了這個作用之外還有其它一些作用,比如可以用來處理CPU異常、用來實現(xiàn)系統(tǒng)調(diào)用,定時器中斷還可以用來實現(xiàn)搶占式多任務(wù)。所以中斷機(jī)制對操作系統(tǒng)來說是非常重要的,重要性就相當(dāng)于人的神經(jīng)系統(tǒng)加呼吸系統(tǒng)一樣重要。
編程設(shè)施:
計算機(jī)除了管理硬件之外,還為軟件提供了兩個編程設(shè)施,分別是線程同步和進(jìn)程間通信。線程同步是因為多個執(zhí)行流(線程)同時訪問公共數(shù)據(jù)引起的,如果不采取一些措施的話就會產(chǎn)生程序錯誤,因此操作系統(tǒng)提供了線程同步這個編程設(shè)施來解決這個問題。線程同步中有一個非常常用的方法叫做自旋鎖。
進(jìn)程間通信是因為有了虛擬內(nèi)存/分頁機(jī)制之后產(chǎn)生了進(jìn)程隔離,進(jìn)程之間無法直接訪問對方,所以需要通過內(nèi)核提供的進(jìn)程間通信機(jī)制來進(jìn)行溝通,具體內(nèi)容請參看《深入理解Linux進(jìn)程間通信》。Linux還有一個重要的機(jī)制叫做信號機(jī)制(signal),它和IPC很像,但又不是典型的IPC,也不僅僅是IPC,它還是系統(tǒng)處理CPU異常的方法。
其它模塊:
操作系統(tǒng)還有兩個重要的模塊:一個是和社會因素有關(guān)的安全防護(hù),一個是和物理因素有關(guān)的電源管理。電源管理包括基本電源管理和高級電源管理,基本電源管理包括:睡眠、休眠、關(guān)機(jī)、重啟,高級電源管理也就是各種省電機(jī)制,如CPUIdle、CPUFrequ、DEVFreq,另外溫控也可以算到電源管理里面。
推薦閱讀:
想要學(xué)習(xí)Linux內(nèi)核的話,推薦以下書籍《Linux Kernel Development》《Understanding the Linux Kernel》《Professional Linux Kernel Architecture》《Mastering Linux Kernel Development》《Understanding the Linux Virtual Memory Manager》《Linux內(nèi)核深度解析》《Linux操作系統(tǒng)原理與應(yīng)用》《深度探索Linux操作系統(tǒng)》《ARM Linux內(nèi)核源碼剖析》《奔跑吧Linux內(nèi)核》《Linux內(nèi)核源代碼情景分析》。
想要學(xué)習(xí)早期版本Linux的,如0.11、0.12,推薦以下書籍《Linux內(nèi)核設(shè)計的藝術(shù)》《Linux內(nèi)核完全注釋》。
還有一些學(xué)習(xí)Linux的網(wǎng)絡(luò)資源:
LWN:https://lwn.net/Kernel/Index/
linux-insides:https://github.com/0xAX/linux-insides
宋寶華:https://blog.csdn.net/21cnbao
蝸窩科技:http://www.wowotech.net
CHENG Jian:https://kernel.blog.csdn.net/
內(nèi)核工匠:https://blog.csdn.net/feelabclihu
DroidPhone:https://blog.csdn.net/DroidPhone
Bystander_J:https://blog.csdn.net/weixin_42092278
術(shù)道經(jīng)緯:https://www.zhihu.com/column/c_1108400140804726784
Kernel Exploring:https://richardweiyang-2.gitbook.io/kernel-exploring/
Linux Performance:http://linuxperf.com/
Linux系統(tǒng)標(biāo)準(zhǔn)規(guī)范:
https://refspecs.linuxfoundation.org/
https://man7.org/linux/man-pages/man7/standards.7.html
六、計算機(jī)運行模型
學(xué)了上面這些知識之后,我們心里要有幾幅計算機(jī)的運行模型圖,達(dá)到計算機(jī)就在我心中運行的境界。一是CPU運行模型圖,二是進(jìn)程調(diào)度圖,三是總體軟件體系結(jié)構(gòu)圖。
6.1 CPU運行模型
最簡單的CPU模型是圖靈機(jī)模型,非常簡單,就是一個一直在線性運行的機(jī)器。其次是帶中斷的圖靈機(jī)模型,這個模型可以在正常的執(zhí)行流之外插入一段額外的執(zhí)行流。然后是具體的CPU運行模型,進(jìn)程一般運行在用戶空間,借助中斷機(jī)制可以陷入內(nèi)核執(zhí)行一些系統(tǒng)調(diào)用,外設(shè)發(fā)生中斷會執(zhí)行中斷處理函數(shù)。
實際的CPU運行模型在這個基礎(chǔ)之上又變得非常復(fù)雜了,如下圖所示。在學(xué)習(xí)了中斷機(jī)制、系統(tǒng)調(diào)用和進(jìn)程調(diào)度之后,對下面這幾張圖應(yīng)該能理解地比較透徹。
我們在這里說一下CPU執(zhí)行場景,場景就是英文中的context,一般都翻譯成上下文,我看到有一本書上翻譯成場景,覺得這個翻譯非常信達(dá)雅,所以后面就用場景這個翻譯了。CPU的執(zhí)行場景一共有兩種:一個是進(jìn)程執(zhí)行場景,一個是中斷執(zhí)行場景。進(jìn)程執(zhí)行場景分為兩種情況:用戶空間進(jìn)程執(zhí)行場景和內(nèi)核空間進(jìn)程執(zhí)行場景。進(jìn)程一般在用戶空間運行,發(fā)生系統(tǒng)調(diào)用時會進(jìn)入到內(nèi)核空間運行。中斷執(zhí)行場景只有一種情況,那就是內(nèi)核空間中斷執(zhí)行場景,因為中斷不能運行在用戶空間。中斷執(zhí)行場景和進(jìn)程執(zhí)行場景還有一個很大的區(qū)別就是進(jìn)程執(zhí)行場景可阻塞可調(diào)度,中斷執(zhí)行場景必須一次性執(zhí)行完,不能阻塞,因為它不可調(diào)度。
6.2 進(jìn)程調(diào)度模型
在CPU運行模型的基礎(chǔ)上,CPU在用戶空間執(zhí)行進(jìn)程,可以通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核空間,也可能由于中斷或者異常發(fā)生而進(jìn)入內(nèi)核空間,在內(nèi)核空間里進(jìn)程可以由于阻塞而主動發(fā)生進(jìn)程調(diào)度,或者在定時器中斷里面由于時間片耗盡而發(fā)生調(diào)度。
圖片展示的是UP(單處理器)調(diào)度的情況,每個時刻最多只有一個進(jìn)程會被選中在CPU上運行。如果是SMP(多處理器)的話,就是有NR_CPU個這樣的圖同時運轉(zhuǎn),互不干擾,這是從運行的角度看是這樣的,但是如果從空間的角度看的話,因為內(nèi)核空間只有一個,所以圖片應(yīng)該是中心捏合在一起,但是翅膀各是各的那種樣式的圖。
對于調(diào)度器是如何選擇進(jìn)程進(jìn)行調(diào)度的,我們心中要有下面這張圖。
6.3 軟件體系結(jié)構(gòu)
下面我們再來看一下整個軟件體系放在一起是什么樣的:
我們可以看到內(nèi)核運行在硬件之上,進(jìn)程運行在內(nèi)核之上,有init等進(jìn)程是作為操作系統(tǒng)的一部分共同維護(hù)整個系統(tǒng)的運行。內(nèi)核里面包括進(jìn)程調(diào)度、內(nèi)存管理、文件系統(tǒng)、BIO層、網(wǎng)絡(luò)模塊、其它驅(qū)動等模塊。進(jìn)程是由一個exe主程序和n個so庫程序組成。每個進(jìn)程中的libc.so,ld.so等庫程序都是屬于操作系統(tǒng)的一部分。所有進(jìn)程通過進(jìn)程調(diào)度共享CPU、輪流執(zhí)行。
審核編輯:湯梓紅
評論
查看更多