我對計算機系統的理解

計算機系統的組成

一個計算機系統是由軟件與硬件組成的,就硬件來講,當咱們通常去電腦城配電腦的時候,通常會購買這些基本零部件:主板,CPU,內存,磁盤,機箱,鍵盤鼠標,顯示器。固然還有一些額外的部件,例如獨立顯卡或者網卡,音箱等。若是除去非必要的部件來看,其實一個計算機系統主要由下面這些重要的部件組成:
CPU,存儲器(內存),磁盤,IO設備(鍵鼠,顯示器),以及鏈接這些器件總線,只不過咱們的成品電腦是用一塊電路板將這些部件鏈接在了一塊兒。固然隨着電腦系統愈來愈強大,可能除了上述部件以外,還多了不少其餘的部件,例如我的PC的主板上可能還有南橋,北橋等等一系列的額外的芯片。可是咱們這裏討論的是組成一個計算機系統最基本的部件,其餘的部分,爲了簡化說明,暫時省略。

CPU:是一個計算機最核心的部分,計算機的全部運算,程序的全部指令的執行是經過CPU來進行的,CPU是計算機的大腦。

存儲器:CPU所執行的指令,計算的中間結果,產生的數據都須要經過某種方式進行保存,方便CPU讀取和存入,這就是存儲器的功能。

磁盤:提供永久保存數據的辦法。

IO:也便是鏈接在計算機上的輸入輸出設備,通常最多見的就是鼠標,鍵盤和顯示器了,固然還有其餘的一些輸入輸出設備,例如打印機,USB外接設備等。IO設備主要提供給人們與計算機進行交互的時候使用。

總線:全部這些部件之間經過總線進行鏈接,有些設備共享一組總線,有的設備之間有專用的總線。

計算機的軟件組成:計算機除了硬件系統以外,在硬件系統之上運行着一系列的軟件,最重要的固然是操做系統軟件,另外還有各類驅動程序用於與特定的設備進行通訊。除此以外還有各類運行在操做系統之上的用戶應用程序。node

程序是如何在計算機上運行的

程序是什麼:
在計算機系統上運行着各類各樣的程序,包括操做系統自己也是程序,那麼程序究竟是什麼呢,程序通常以文件的形式存在於磁盤上,這些文件是具備必定結構的二進制文件,這些文件被以一種特定含義的格式進行組織,例如典型的二進制的可執行文件(無論是windows仍是linux系統)以必定的結構描述,在這些描述中,該文件被分紅了多個段,每一個段中的數據內容具備不一樣的含義,例如數據段,代碼段,符號表等等。其中代碼段中的二進制數據,咱們認爲就是CPU直接執行的指令。

CPU的指令是什麼:
一條CPU的指令是一串不定長的二進制的位串,而當CPU讀取這一個位串並執行的時候,通常是運行一個特定的功能,例如加法,減法,從內存讀取一個字節到寄存器等等這樣的功能,而一個CPU可以執行的全部二進制位串(也就是指令)的集合則是CPU的指令集。不一樣的硬件廠商生產的CPU他們可以識別執行的二進制位串序列集(CPU指令)多是不同的。而一樣的功能,例如加法功能,不一樣的CPU須要執行的二進制位串多是不同的。例如咱們常見的PC機器的x86架構的CPU基本上是兼容的,目前市面上主流的PC端的CPU由Intel和AMD生產,這兩個廠家生產的CPU的指令基本上是兼容的,可是也可能各自有一些特定的指令是對方沒有的。另外的例如Arm或者mips的CPU的指令集則與x86體系是不一樣的,而前者多用於嵌入式系統。

CPU的硬件自己能夠理解爲是一系列的電路,該電路實現必定的功能,該電路中又分紅了不少的功能單元,例如在現代CPU的設計中,一條計算機指令在執行的時候,會通過:取指、譯碼、執行、訪存,寫回,更新PC等階段,而現代CPU被設計成以流水線的方式執行指令。如前所述,一條指令是若干個二進制bit位的位串,在取指階段CPU根據程序計數器(PC)中的地址取出當前須要執行的指令。接着對該指令譯碼,所謂譯碼則是解析該指令,通常一條指令被分紅了多個部分,每一個部分表明不一樣的含義,一條IA32的指令是由1到15個字節組成,操做數較少的指令所須要的字節數少,那些不太經常使用的或者操做數較多的指令所須要的字節數較多。在執行階段由CPU的算術/邏輯單元執行指令。訪存階段將數據寫入存儲器或者從存儲器中讀出數據。寫回階段將結果寫到寄存器中。更新PC階段則將PC計數器設置成下一條指令的地址。

程序的編譯與連接過程:
一個程序的生成流程能夠大體描述爲:程序文本文件、編譯成彙編文件(.s)、編譯成二進制文件(.obj)、連接成最終的可執行文件。CPU只能識別並執行他的指令集中的位串,因此咱們必須將程序員能夠識別的文本文件的程序代碼轉換成CPU可以執行的一系列的指令,這個轉換過程就是編譯過程。而連接是一個很是複雜的過程,其中包括靜態連接和動態連接,連接的過程是將全部模塊中使用的符號替換成實際使用的內存地址的過程(而其實現代操做系統中程序訪問的內存地址並非實際的物理地址,而是虛擬地址)。靜態連接是在編譯階段由連接器完成連接過程直接生成可執行程序的過程。動態連接是在程序執行階段動態將程序中的符號替換成爲實際的內存地址的過程,例如咱們的C程序裏面通常調用了C的標準庫函數,而C的標準庫函數是在其動態連接庫libc.so中的,在咱們的程序執行的時候,會將libc.so所在的內存地址映射到程序的虛擬地址空間,並修改程序中全部訪問libc.so中的符號爲正確的訪問地址的過程。這個過程就是動態連接。

程序的執行過程:
一個程序要想被執行,首先要將其文件內容加載到內存中,而後CPU從程序的代碼段的入口點的第一條指令開始執行,後面的全部執行過程都是按照程序中的指令進行的,一直到程序結束爲止。這一整個過程實際上並無這幾句話描述的這麼簡單,首先程序被從磁盤讀取到內存這一過程,可能涉及到磁盤的IO中斷,DMA的拷貝,虛擬內存等,當程序被加載進內存以後,若是程序使用了動態鏈接庫,例如最簡單的C程序也可能連接了C的標準庫,因此還須要加載動態庫(通常是經過內存映射的方式),將動態庫加載進內存,並將其映射到程序的虛擬地址空間中。最後通過一些初始化以後(初始化寄存器,庫的初始化等),開始從程序的入口處的指令執行。linux

操做系統是什麼

什麼是操做系統呢,通常狀況下咱們提到操做系統就認爲高深莫測,深不見底。其實操做系統的做用能夠從這麼幾個方面來理解,首先操做系統的一個很是重要的功能便是提供用戶接口,也就是說當人們要使用計算機的時候,必須經過一種方式來控制計算機,那麼操做系統提供了這樣的方式來令人們能夠控制計算機,例如命令行的或者是UI的方式,這種接口咱們能夠理解爲使用計算機的入口。另一種接口用於擴展計算機的功能,例如程序員編寫程序的時候就會使用操做系統提供的系統接口,這種接口是更底層的概念。

其實咱們說的用戶接口不必定是操做系統的一部分,例如典型的linux類型的操做系統,其桌面環境是能夠不用的,或者是能夠隨意替換的,其shell命令行環境也能夠本身替換,在linux中有多種可使用的shell,而惟一不能改變的是linux內核,這麼說來linux的桌面環境以及shell命令行環境好像並不屬於操做系統,可是倒是計算機中不可缺乏的。而在windows操做系統中,特別是windows xp 和windows NT 中其GUI界面是夾在內核中的,這樣一來其又是操做系統的一部分了。因此其實從功能上來講現代操做系統的軟件界限實際上是愈來愈模糊了。

操做系統除了提供用戶接口以外,仍是計算機系統的管理者,負責管理各類軟硬件資源,制定計算機世界的規則,例如操做系統管理CPU,調度各類進程,線程來使CPU執行指令。管理內存,提供進程訪問內存的規則,還有磁盤,外設等設備的管理。若是沒有這些管理,咱們的程序能夠亂執行,誰先執行,誰後執行? 執行多久?內存區域能夠亂寫,我能夠破壞你的內存,你能夠破壞個人內存。就像在道路上沒有警察去約束,那交通確定是一片混亂。

什麼是驅動程序呢,驅動程序嚴格的來講並非一個單獨的程序,也不是一個獨立運行的進程,實際上咱們能夠理解驅動程序是一個程序片斷,或者是一個符合必定約定提供約定接口的程序庫,操做系統調用該庫中提供的接口,去操做特定的硬件。該庫實現了對特定硬件的操做,並提供一個對外的接口供操做系統調用。例如對於磁盤來講,生產磁盤的硬件廠商必定會提供從磁盤讀取或者寫入磁盤數據的辦法,該辦法(多是一系列的底層C接口)可能很複雜,須要不少個步驟,尋址,尋道等。並且不一樣的磁盤廠商提供的底層接口並不必定相同,那麼磁盤驅動程序封裝了這些底層的操做磁盤的功能,並對外提供統一的操做接口(該接口規範是操做系統規定的,這樣操做系統才能統一調用)。那麼符合規定接口的該軟件庫咱們能夠認爲就是驅動,有的驅動程序是隨操做系統啓動的時候進行加載的,而有的能夠直接即時安裝進行動態加載,這有賴於動態連接庫的運行時加載功能。程序員

進程與線程

什麼是進程呢,咱們的程序其實是一個二進制文件存放在磁盤中,當將程序載入到內存中,並從第一條指令開始執行,一直到最後一條指令結束該程序文件中的指令再也不被CPU執行,那麼該程序的這一次的運行過程,咱們能夠理解爲是一個進程。也就是說一個進程是一個二進制的程序中的指令從第一條指令被CPU執行,一直到最後一條指令被CPU執行的這整個過程。進程是一個磁盤中的程序運行的實例。

一個程序文件是一個具備必定結構的二進制文件,通常狀況下不一樣的操做系統的二進制文件的結構是不一樣的,可是其大致概念是類似的,例如linux和windows程序文件都包含有代碼段,數據段,符號表等等區域。程序文件中除了代碼段中的二進制數據是CPU真正要執行的指令之外,其餘的段要麼是在CPU執行過程當中須要使用到的內存信息(例如變量),要麼是編譯器調試的時候須要用到的輔助信息(例如符號表)。

在操做系統中有一些信息是與一個運行的程序,也就是進程相關聯的,通常咱們稱之爲PCB(進程控制塊),該信息中描述了進程在運行過程與該進程關聯的信息,例如進程的ID,程序計數器,堆棧等等。

一般每個進程有一個地址空間和一個控制線程(主線程),固然一個進程中能夠有多個控制線程,這些線程就像分離的進程同樣,只不過他們共享同一個進程的地址空間以及其餘資源。在內存中也有一個信息結構來記錄與每一個線程關聯的信息,例如程序計數器,堆棧信息等。

進程是資源分配的最小單位,線程是CPU調度的最小單位。算法

單線程與多線程程序、併發

一個程序究竟是單線程結構好仍是多線程好呢?從CPU的角度上來看,若是是單核CPU在任什麼時候刻,只能運行一個進程,也就是說只能調度一個線程(若是是單線程的程序則運行進程的時候實際上調度的是該進程的主線程),單核CPU的多任務併發其實是僞併發,任什麼時候刻只有一個進程處於運行中,只不過CPU的運行很快,多個進程能夠輪番獲得CPU,看起來好像是同時運行的同樣。線程是CPU調度的最小單位,任什麼時候刻只有一個線程得到CPU運行,因此理論上多個線程運行的時候多了線程上下文切換的開銷,應該比單線程的進程效率低。可是因爲複雜程序的業務邏輯,單線程程序中若是有阻塞的邏輯,則反而由於阻塞,該線程被操做系統切換出去,不能獲得CPU,而下降了程序獲得CPU的時間,另外單線程程序的設計每每比較複雜,由程序設計帶來的複雜性可能會抵消多線程上下文切換的損失。因此通常狀況下當程序中有比較耗時的操做時,單線程程序是不合適的,應該用多線程比較好。若是是CPU密集型的程序,加上良好的程序設計,則使用單線程的結構效率比較高(單線程的程序通常使用狀態機來驅動程序的運行)。而即便多線程的程序有本身的優勢,也並非線程越多越好,當線程很是多的時候線程上下文切換的開銷就比較可觀了。現代計算機通常都擁有多核CPU,從這點上來說多線程的程序更能取得比較高的CPU利用率。shell

存儲管理

存儲器是計算機系統中的重要組成部分,一個程序要執行,必須先從磁盤拷貝到內存上,而後從內存中讀取計算機指令進行執行。而計算機存儲的使用歷史也是伴隨着計算機以及操做系統的發展變化的。

最開始的操做系統是單任務的操做系統,某一時刻只有一個進程在執行,也沒有線程的概念。因此程序中使用的地址都是實際的物理地址,而該物理地址是編譯器在編譯階段分配的。程序在運行以前被載入內存中而後被執行。

隨着用戶不知足於只運行一個程序,多個程序開始被同時執行,那麼此時程序中的地址就不可能使用實際的物理地址了,由於要保證兩個程序同時執行互相不產生干擾的話,他們就不該該同時訪問相同的物理地址,而若是此時程序中使用的地址仍是實際的物理地址而且須要保證程序訪問的地址空間不會重疊,在編譯階段編譯器幾乎不可能實現。編譯器可能的實現方式是使用相對地址,而程序只須要在運行階段知道一個基地址,程序中的其餘地址則經過基地址加上偏移地址(也就是相對地址由編譯階段填到程序中)的方式來實現。固然也會有一個寄存器去記錄程序訪問內存的最大邊界,以防止程序訪問越界。這種方式解決了多個程序同時運行的內存分配問題,使用統一的方式來分配內存,也下降了編譯器編譯的複雜度。

若是內存空間無限大,使用基地址加上偏移地址的方式便可解決內存的分配問題。而實際上雖然即便如今內存空間愈來愈大,可是隨着程序愈來愈大,用戶要求同時運行的程序愈來愈多,要想在程序運行以前將全部程序載入到內存,以如今的內存空間恐怕是辦不到的,特別是有的程序動則以G爲單位。爲了適應這樣的需求,出現了內存交換的技術,其實現過程是這樣的,例若有3個程序須要運行,先載入程序A運行,再載入程序B運行,此時再載入C運行,然而剩餘的內存空間不夠載入C程序,此時能夠選擇將B程序運行的全部內存映像交換到磁盤空間保存,這樣B程序佔用的內存空間被釋放,而後載入C程序運行,如此反覆。這種方式就是內存交換技術。可是即便採用內存交換技術,也只能解決一部分問題,另外即便現代磁盤的傳輸速度愈來愈快,可是頻繁的內存交換,仍然會大大影響程序的性能,特別是當運行的程序很大的時候,例如將1G的程序交換到磁盤上,即便SATA磁盤傳輸的峯值是100MB/s也仍然須要10秒才能完成交換操做,而將該程序載入到內存中從新運行也須要一樣的時間。

現代操做系統採起另一種方式來作這樣的操做,即將程序分割成不少的小塊,每一小塊的大小或是4K,或是8K,16K,32K等,每次載入程序的時候以塊爲單位載入。這些分塊操做所有由計算機完成,不須要程序員干預,這種方式被稱爲虛擬內存。每一個程序有本身的地址空間,這個空間被分割成多個塊,每一個塊稱爲一個頁或者頁面,每一頁有連續的地址範圍。這些頁被映射到物理內存,而並不要求全部的頁都在內存中才能運行程序,當程序引用到的地址在實際的物理內存中有對應的映射的時候,由硬件來翻譯該地址爲實際的物理地址,若是沒有對應的映射,則會引起一個缺頁中斷,由操做系統負責將缺失的部分載入到物理內存並從新執行失敗的指令。

程序使用的地址空間叫虛擬地址空間,虛擬地址空間中的地址都是虛擬地址,其地址範圍能夠從0到最大的物理內存地址,例如物理內存是4G,那麼程序的虛擬地址空間是0-4G,每一個程序都是這樣。那麼若是同時運行多個程序會怎樣呢,這樣兩個程序均可以訪問到最大的4G內存,若是他們訪問的是同一個地址會怎麼樣?在實際運行過程當中,虛擬地址會被一個叫作MMU(內存管理單元)的設施翻譯成爲實際的物理地址,也就是說每個程序使用的虛擬地址都會被映射到實際的物理地址,而兩個程序中相同虛擬地址會被映射到不一樣的物理地址,這樣就不存在訪問衝突的問題了。程序的虛擬地址空間是相同的,這給編譯器的編寫帶來了極大的方便,生成的程序代碼使用統一的地址空間模型,地址的翻譯工做交給了MMU與操做系統。

以上其實是現代計算機採用的內存運行模型,實際上這是最基本的原理,還有一些其餘的細節,例如程序的虛擬地址空間被分紅多個頁,每一個頁會映射到實際的物理地址頁,而物理地址頁咱們稱爲頁框,頁與頁框的大小通常是相同的,而頁與頁框的映射關係表則稱爲頁表。關於頁到頁框的解析也是一個複雜過程,在頁表項中的各類二進制位用於解析頁到頁框的映射。

當發生缺頁中斷的時候,由操做系統負責載入缺失的頁面到物理內存中,固然若是內存夠的話是沒有任何問題的,若是在內存不夠的狀況下,則必需要作出選擇將內存中的其餘頁交換到磁盤中,這樣騰出空間給即將加載的頁,當操做系統成功加載須要的頁以後,會從新修改頁表中的映射關係,並執行引起缺頁中斷的指令,繼續原來程序的執行過程。那麼操做系統如何選擇將哪些頁面交換到磁盤以騰出內存空間呢,這種選擇的策略則是頁面置換算法的內容。現代操做系統有多種頁面置換算法,並不會單純的採用某一種算法,而是綜合使用。例如最優頁面置換,最近未使用頁面置換,先進先出頁面置換,時鐘頁面置換,最近最少使用頁面置換等等。

由於有了虛擬內存的存在,能夠將同一個物理內存映射到兩個不一樣程序的虛擬地址空間中,這樣兩個程序能夠同時讀寫該塊物理內存區域,這就是共享內存。一樣能夠將虛擬地址空間映射到一個文件,這樣程序能夠像操做內存同樣方便的讀寫一個文件,這是內存映射文件。windows

文件系統

什麼是文件系統呢,在說明這個概念以前,咱們先說說文件是怎麼存儲的,咱們以存儲介質硬盤爲例,硬盤的物理結構是由不少盤片組成的,每個盤片有兩面,每一面由一圈一圈的同心圓組成的磁道,而將多個盤片疊在一塊兒以後,全部疊在一塊兒的盤片上的同一個位置的同心圓組成一個圓柱體,這個由全部盤片上相同的磁道組成圓柱稱爲柱面。而每個盤片上的每個磁道被分割成一些等分的圓弧,這些圓弧叫扇區。在物理上經過電磁的原理從磁盤讀寫數據,咱們能夠認爲能夠將0,1這兩種不一樣的狀態記錄到磁盤的磁道上,而這些連續的0,1的狀態就是計算機中的二進制位流。因此能夠認爲在磁道上存儲的就是表示不一樣狀態的二進制位流數據。那麼整個磁盤是由多個盤片組成的,每一個盤片上有不少磁道,如何組織這些數據呢?就必需要對全部的盤片,柱面,扇區,磁道進行標識,而且方便查找與讀寫。也就是說須要用一個結構或者一組規則來組織他們,這就是文件系統。

文件系統是操做系統用於明確存儲設備或分區上的文件的方法和數據結構,也就是存儲設備上組織文件的方法,從系統角度看,文件系統是對文件存儲設備的空間進行組織和分配,負責文件存儲並對存入的文件進行保護和檢索的系統。具體的說,它負責爲用戶創建文件,存入、讀出、修改、轉儲文件,控制文件的存取,當用戶再也不使用時撤銷文件等。

若是沒有文件系統這樣的組織規則,那麼咱們看磁盤則是一連串的無心義的二進制位流數據,咱們分不清楚哪裏是開始,哪裏是結束,這些二進制位流信息的含義。就好像一個doc文檔,咱們使用二進制編輯軟件打開以後看到的就是一連串毫無心義的二進制位流同樣,然而使用doc文檔的結構規則來解析這些位流信息的含義,咱們能夠解析出該doc文檔中的文字,圖片,以及格式等信息。而文件系統也起到相似的做用,文件系統自己也佔用磁盤空間,是存放在磁盤上的。多數磁盤劃分爲一個或多個分區,每一個分區中均可以有一個獨立的文件系統。磁盤的0號扇區稱爲主引導記錄(MBR),用來引導計算機。在MBR的結尾是分區表。該表給出了每一個分區的起始和結束地址。表中的一個分區被標記爲活動分區,在計算機被引導時,BIOS讀入並執行MBR。MBR作的第一件事是肯定活動分區,讀入它的第一個塊,稱爲引導塊,並執行之。引導塊中的程序將裝載該分區中的操做系統。

每個磁盤分區由引導塊、超級塊、空閒空間管理、i節點、根目錄、其餘文件和目錄的順序組成。超級塊包含文件系統的全部關鍵參數,在計算機啓動的時候或者該文件系統首次使用時,把超級塊讀入內存。超級塊中的典型信息包括:肯定文件系統類型用的魔數、文件系統中數據塊的數量以及其餘重要的管理信息。

在讀文件前必須先打開文件,打開文件時,操做系統利用用戶給出的路徑找到相應的目錄項,目錄項中提供了查找文件磁盤塊所須要的信息。而文件的屬性信息能夠存放在目錄項中或者存放在文件的i節點的信息中。而這些目錄項以及i節點存放在物理磁盤的哪一個柱面,哪一個磁道,哪一個扇區的信息是能夠在i節點信息以及從根目錄根據路徑層層查找的目錄項信息中獲得的。

光盤的存儲方式與磁盤相似,只不過光盤使用的介質並非磁介質,而是其餘類型的介質,因此光盤沒有磁道的概念,光盤其實是經過一個螺旋狀的相似於磁道的軌跡來存儲數據的,在這條軌跡上記錄了0,1兩種不一樣狀態的位流數據。因爲光盤的存儲特性,光盤上的文件系統與磁盤使用的文件系統是有不一樣的,具體能夠查閱光盤相關的格式與文件系統文檔,可是其思路與磁盤文件系統是相似的。網絡

輸入輸出(IO)

操做系統管理者各類各樣的鏈接到計算機上的輸入輸出設備,IO設備能夠分爲兩類,塊設備和字符設備,塊設備把信息存儲在固定大小的塊中,每一個塊有本身的地址。一般塊的大小在512字節和32768字節之間。全部傳輸以一個或多個完整的塊爲單位。塊設備的基本特徵是每一個塊都能獨立於其餘的塊進行讀寫。硬盤,CD-ROM,USB盤是常見的塊設備。另外一種設備是字符設備,字符設備以字符爲單位發送或接受一個字符流,而不考慮任何塊結構。字符設備是不可尋址的,也沒有尋道操做。打印機,網絡接口,鼠標,以及大多數與磁盤不一樣的設備均可以看做是字符設備。

IO設備通常由機械部件和電子部件兩部分組成,電子部件稱做設備控制器或者適配器。在我的計算機上它常常以主板上的芯片的形式出現,或者以插入(PCI)擴展槽中的印刷電路板的形式出現。機械部件則是設備自己。

控制器與設備之間的接口是一個很低層次的接口。以磁盤設備爲例,從設備中出來的是一個串行的位流,控制器的任務是把串行的位流轉換爲字節塊,並進行必要的錯誤校訂工做,字節塊一般首先在控制器內部的一個緩衝區按位進行組裝,而後進行校驗證實字節塊沒有錯誤以後,將它複製到主存中。

CPU如何從設備中讀取數據(例如磁盤)或寫數據到設備中呢? CPU從磁盤讀寫數據是直接與磁盤的設備控制器(也就是磁盤適配器)進行數據交互的,每一個設備控制器中有幾個寄存器用來與CPU進行通訊,經過寫入這些寄存器,操做系統能夠命令設備發送數據,接收數據,開啓或者關閉,或者執行其餘操做。經過讀取這些寄存器的值,操做系統能夠知道設備當前的狀態。除了設備控制器中的寄存器以外,許多設備還有一個操做系統能夠讀寫的數據緩衝區,能夠供程序或者操做系統讀寫數據。那麼操做系統要操做這些控制寄存器,就須要有一個地址來標識這些控制寄存器,有兩種方式對控制寄存器進行地址編號,一種是爲每一個控制寄存器分配一個IO端口號,全部IO端口造成IO端口空間,該端口空間獨立於內存的地址空間,是徹底不一樣的。IO端口空間受到保護使普通的用戶程序不能訪問,只有操做系統能夠訪問。CPU能夠經過這些IO端口號來讀寫控制寄存器的內容,從而達到與設備控制器通訊的目的。另外一種是將IO端口號映射到內存的地址空間,每一個控制寄存器被分配一個內存地址,這樣的系統稱爲內存映射IO。一般分配給控制寄存器的地址位於內存地址的頂端,而且該地址不會再分配給應用程序。在這種模式下,IO端口的地址與內存地址是一個地址空間,並非獨立的。這種模式的好處是,不須要使用特定的指令去操做控制寄存器,只須要普通的訪問內存的指令便可以對控制寄存器進行讀寫操做,就像程序中普通讀寫內存同樣。

上面講述了CPU如何與設備進行通訊的原理,那麼讀寫文件的具體過程是怎麼樣的呢? 通常狀況是這樣的,在程序中咱們通常經過系統提供的read,write函數對文件進行讀寫,固然在讀寫以前通常會有一個open操做(傳遞一個文件路徑,以及打開的方式),讀寫完成以後通常會有一個close操做關閉文件。當使用open操做打開一個文件的時候,最終會調用到文件系統的相關接口,而且返回的文件描述符與文件的inode節點信息在操做系統的內核中確定有對應的關聯關係,此後在read或者write的時候傳遞進去的文件描述符,最後應該被文件系統關聯到文件相關的底層結構例如inode信息,經過inode信息就能夠操做該文件在磁盤上的塊了(文件系統應該有查找文件的第幾個字節在磁盤的哪一個塊上的能力)。在write或者read的時候,CPU先通知磁盤設備控制器,設備控制器從磁盤尋道,尋址,一位一位的讀取某一個塊(或者是以扇區爲單位),直到將整個塊讀入到控制器的內部緩衝區中,計算校驗和,保證沒有錯誤。而後控制器產生一箇中斷,等到操做系統響應的時候,CPU從設備控制器的緩衝中一個字節一個字節的讀取數據,並拷貝到內存中(read的時候會指定一個buffer,也就是數據要讀到的內存地址)。這種模式是IO操做模式中的一種。下面說說IO實現的三種方法。

第一種方法是程序控制IO,程序須要輪詢IO設備的狀態,以查看IO設備是否準備好,例如打印機,程序須要輪詢打印機中的寄存器,以查看打印機是否準備好接受打印的字符,若是準備好,程序將須要打印的字符拷貝到打印機的緩衝區中,若是打印機此時開始打印一個字符,並同時設置打印機的狀態爲非就緒,在打印機打印該字符的過程當中,程序必須一直查詢並等待打印機完成該字符的打印直到打印機完成該字符的打印過程以後,其寄存器中表示打印機狀態的值被改成就緒狀態,程序拷貝第二個須要打印的字符到打印機的緩衝區中。如此循環,直到全部打印完成爲止。這種模式浪費了大量的CPU時間,由於打印機打印的過程是一個耗時的過程,而在CPU等待打印機打印字符的過程,將大量的CPU週期浪費在輪詢打印機的狀態上,這就出現了第二種方式。

第二種方式是中斷驅動的IO,當打印機開始打印第一個字符的時候,CPU去作其餘事情(與當前打印相關的進程被調度到阻塞狀態,其餘的進程或者線程得到CPU),打印機完成第一個字符的打印以後,發出一箇中斷,中斷處理程序運行,以前被掛起的進程從新開始運行,拷貝第二個須要打印的字符給打印機,如此反覆。在這種模型下,因爲IO設備的操做很慢(例如打印機的打印操做),在IO設備執行操做的時候CPU沒必要等在那裏,而是能夠作其餘事情,等IO操做完成以後,以中斷的方式通知,這樣大大的節約了CPU的時鐘週期。這種方式的缺點是每一次IO設備的讀寫都會產生中斷,中斷髮生在每一個字符上。並且中斷是須要花費時間的,因此這一方法將浪費必定量的CPU時間。

第三種方式是使用DMA(直接存儲器存取),讓DMA控制器來操做IO而不是CPU。本質上DMA是程序控制IO,只不過是由DMA控制器而不是主CPU作所有工做。其實咱們能夠想象成DMA是一個特定功能的CPU,該特定功能也便是對IO設備的操做。將原來須要CPU進行IO操做的部分,放到DMA控制器上實現。而對於IO設備來講,例如磁盤控制器並不知道或者並不關心,磁盤的讀寫請求是來自CPU仍是DMA控制器。當程序須要將文件中的某些字節拷貝到內存中的一塊區域時,首先CPU告訴DMA控制器須要將什麼數據傳送到什麼地方,而該進程(或者當前請求IO的線程)被掛起阻塞,接着DMA控制器向磁盤控制器發出命令,磁盤控制器尋道,尋址,將數據拷貝到磁盤控制器的緩衝區中。接着DMA控制器在總線上發出一個讀請求給磁盤控制器,開始DMA傳送。傳輸完成以後DMA控制器將中斷CPU,以讓CPU知道傳輸已經完成。接着中斷服務程序開始運行,以前被掛起的進程(線程)繼續開始運行,而此時文件的內容已經讀到了指定的內存地址了。這期間沒有佔用CPU的時鐘週期。數據結構

總結與其餘

計算機系統是一個很是複雜與龐大的系統,以上的內容僅僅是一個入門的指引,限於篇幅不少細枝末節的內容都沒有提到,若是有任何錯誤歡迎你們指出。另外計算機網絡自己是一個很是大的課題因此我但願用單獨的一篇文章進行說明。另外留下一個問題,也是我有疑惑的地方,若是你們有答案,能夠在留言區域討論。多線程

問題:在單核CPU的架構下,多線程之間的鎖其實相對比較容易實現,由於任什麼時候刻其實只有一個進程的一個線程在佔用CPU,所謂的併發其實是僞併發,真正的多核CPU的併發叫並行。單核CPU狀況下,因爲CPU輪轉的很是快,讓咱們看起來是同時運行了多個程序,那麼問題是,若是在多個CPU的狀況下,原來寫的多線程程序的互斥與同步還有效果嗎?由於極可能一個進程中的兩個線程同時在兩個不一樣CPU上執行,他們訪問同一個變量,這個加鎖還有效果嗎?架構

相關文章
相關標籤/搜索