备战秋招——操作系统
?
進程與線程:
概念:
線程:是操作系統(tǒng)能夠進行運算調度的最小單位。是進程中的一個執(zhí)行流程,一個進程中可以運行多個線程。
進程:一個執(zhí)行中的程序的實例。
?
進程 與 線程 的區(qū)別
進程在執(zhí)行過程中擁有獨立的內存單元,而多個線程共享內存
進程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其它進程產(chǎn)生影響,而線程只是一個進程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對于一些要求同時進行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進程。
?
進程在執(zhí)行過程中擁有獨立的內存單元,而多個線程共享進程的內存。(資源分配給進程,同一進程的所有線程共享該進程的所有資源。同一進程中的多個線程共享代碼段(代碼和常量),數(shù)據(jù)段(全局變量和靜態(tài)變量),擴展段(堆存儲)。但是每個線程擁有自己的棧段,棧段又叫運行時段,用來存放所有局部變量和臨時變量。
進程是資源分配的最小單位,線程是CPU調度的最小單位;
系統(tǒng)開銷: 由于在創(chuàng)建或撤消進程時,系統(tǒng)都要為之分配或回收資源,如內存空間、I/o設備等。因此,操作系統(tǒng)所付出的開銷將顯著地大于在創(chuàng)建或撤消線程時的開銷。類似地,在進行進程切換時,涉及到整個當前進程CPU環(huán)境的保存以及新被調度運行的進程的CPU環(huán)境的設置。而線程切換只須保存和設置少量寄存器的內容,并不涉及存儲器管理方面的操作。可見,進程切換的開銷也遠大于線程切換的開銷。
通信:由于同一進程中的多個線程具有相同的地址空間,致使它們之間的同步和通信的實現(xiàn),也變得比較容易。進程間通信IPC,線程間可以直接讀寫進程數(shù)據(jù)段(如全局變量)來進行通信——需要進程同步和互斥手段的輔助,以保證數(shù)據(jù)的一致性。在有的系統(tǒng)中,線程的切換、同步和通信都無須操作系統(tǒng)內核的干預
進程間不會相互影響 ;線程一個線程掛掉將導致整個進程掛掉
?
進程間通信
在 linux 下進程間通信的幾種主要手段簡介:
管道(Pipe)及有名管道(named pipe):管道:傳輸資源。本質上是內核的一塊緩沖區(qū)。(特性:半雙工,單向通信)。 Linux一切皆文件,操作系統(tǒng)為管道提供操作的方法:文件操作。管道可用于具有親緣關系進程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關系進程間的通信;
消息隊列(Message):
消息隊列實際上是操作系統(tǒng)在內核為我們創(chuàng)建的一個隊列,通過這個隊列的標識符key,每一個進程都可以打開這個隊列,每個進程都可以通過這個隊列向這個隊列中插入一個結點或者獲取一個結點來完成不同進程間的通信。
用戶組織一個帶有類型的數(shù)據(jù)塊,添加到隊列中,其他的進程從隊列中獲取數(shù)據(jù)塊,即消息隊列發(fā)送的是一個帶有類型的數(shù)據(jù)塊;消息隊列是一個全雙工通信,可讀可寫(可以發(fā)送數(shù)據(jù),也可以接受數(shù)據(jù))。
消息隊列是消息的鏈接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程可以向隊列中添加消息,被賦予讀權限的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等缺點。
** 共享內存**:使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。
信號量(semaphore):主要作為進程間以及同一進程不同線程之間的同步手段。
套接口(Socket):更為一般的進程間通信機制,可用于不同機器之間的進程間通信。起初是由Unix系統(tǒng)的BSD分支開發(fā)出來的,但現(xiàn)在一般可以移植到其它類Unix系統(tǒng)上:Linux和System V的變種都支持套接字。
各種通信方式的比較和優(yōu)缺點:
管道:速度慢,容量有限,只有父子進程能通訊
有名管道(named pipe):任何進程間都能通訊,但速度慢
消息隊列:容量受到系統(tǒng)限制,且要注意第一次讀的時候,要考慮上一次沒有讀完數(shù)據(jù)的問題
信號量:不能傳遞復雜消息,只能用來同步
共享內存:能夠很容易控制容量,速度快,但要保持同步,比如一個進程在寫的時候,另一個進程要注意讀寫的問題,相當于線程中的線程安全,當然,共享內存區(qū)同樣可以用作線程間通訊,不過沒這個必要,線程間本來就已經(jīng)共享了同一進程內的一塊內存
進程間通信主要包括管道、系統(tǒng)IPC(包括消息隊列、信號量、信號、共享內存等)、以及套接字socket。
1.管道:
管道主要包括無名管道和命名管道:管道可用于具有親緣關系的父子進程間的通信,有名管道除了具有管道所具有的功能外,它還允許無親緣關系進程間的通信
1.1 普通管道PIPE:
1)它是半雙工的(即數(shù)據(jù)只能在一個方向上流動),具有固定的讀端和寫端
2)它只能用于具有親緣關系的進程之間的通信(也是父子進程或者兄弟進程之間)
3)它可以看成是一種特殊的文件,對于它的讀寫也可以使用普通的read、write等函數(shù)。但是它不是普通的文件,并不屬于其他任何文件系統(tǒng),并且只存在于內存中。
1.2 命名管道FIFO:
1)FIFO可以在無關的進程之間交換數(shù)據(jù)
2)FIFO有路徑名與之相關聯(lián),它以一種特殊設備文件形式存在于文件系統(tǒng)中。
?
2. 系統(tǒng)IPC:
2.1 消息隊列
消息隊列,是消息的鏈接表,存放在內核中。一個消息隊列由一個標識符(即隊列ID)來標記。 (消息隊列克服了信號傳遞信息少,管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等特點)具有寫權限得進程可以按照一定得規(guī)則向消息隊列中添加新信息;對消息隊列有讀權限得進程則可以從消息隊列中讀取信息;
特點:
1)消息隊列是面向記錄的,其中的消息具有特定的格式以及特定的優(yōu)先級。
2)消息隊列獨立于發(fā)送與接收進程。進程終止時,消息隊列及其內容并不會被刪除。
3)消息隊列可以實現(xiàn)消息的隨機查詢,消息不一定要以先進先出的次序讀取,也可以按消息的類型讀取。
2.2 信號量semaphore
信號量(semaphore)與已經(jīng)介紹過的 IPC 結構不同,它是一個計數(shù)器,可以用來控制多個進程對共享資源的訪問。信號量用于實現(xiàn)進程間的互斥與同步,而不是用于存儲進程間通信數(shù)據(jù)。
特點:
1)信號量用于進程間同步,若要在進程間傳遞數(shù)據(jù)需要結合共享內存。
2)信號量基于操作系統(tǒng)的 PV 操作,程序對信號量的操作都是原子操作。
3)每次對信號量的 PV 操作不僅限于對信號量值加 1 或減 1,而且可以加減任意正整數(shù)。
4)支持信號量組。
2.3 信號signal
信號是一種比較復雜的通信方式,用于通知接收進程某個事件已經(jīng)發(fā)生。
2.4 共享內存(Shared Memory)
它使得多個進程可以訪問同一塊內存空間,不同進程可以及時看到對方進程中對共享內存中數(shù)據(jù)得更新。這種方式需要依靠某種同步操作,如互斥鎖和信號量等
特點:
1)共享內存是最快的一種IPC,因為進程是直接對內存進行存取
2)因為多個進程可以同時操作,所以需要進行同步
3)信號量+共享內存通常結合在一起使用,信號量用來同步對共享內存的訪問
?
3. 套接字SOCKET:
socket也是一種進程間通信機制,與其他通信機制不同的是,它可用于不同主機之間的進程通信。
?
?
線程間通信的方式:
1、臨界區(qū):
通過多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數(shù)據(jù)訪問;
2、互斥量 Synchronized/Lock:
采用互斥對象機制,只有擁有互斥對象的線程才有訪問公共資源的權限。因為互斥對象只有一個,所以可以保證公共資源不會被多個線程同時訪問
3、信號量 Semphare:
為控制具有有限數(shù)量的用戶資源而設計的,它允許多個線程在同一時刻去訪問同一個資源,但一般需要限制同一時刻訪問此資源的最大線程數(shù)目。
4、事件(信號),Wait/Notify:
通過通知操作的方式來保持多線程同步,還可以方便的實現(xiàn)多線程優(yōu)先級的比較操作
?
?
并發(fā)(concurrency)和并行(parallelism)
并發(fā)(concurrency):指宏觀上看起來兩個程序在同時運行,比如說在單核cpu上的多任務。但是從微觀上看兩個程序的指令是交織著運行的,你的指令之間穿插著我的指令,我的指令之間穿插著你的,在單個周期內只運行了一個指令。這種并發(fā)并不能提高計算機的性能,只能提高效率。
并行(parallelism):指嚴格物理意義上的同時運行,比如多核cpu,兩個程序分別運行在兩個核上,兩者之間互不影響,單個周期內每個程序都運行了自己的指令,也就是運行了兩條指令。這樣說來并行的確提高了計算機的效率。所以現(xiàn)在的cpu都是往多核方面發(fā)展。
?
?
有了進程,為什么還要有線程?
線程產(chǎn)生的原因:
進程可以使多個程序能并發(fā)執(zhí)行,以提高資源的利用率和系統(tǒng)的吞吐量;但是其具有一些缺點:
進程在同一時間只能干一件事
進程在執(zhí)行的過程中如果阻塞,整個進程就會掛起,即使進程中有些工作不依賴于等待的資源,仍然不會執(zhí)行。
?
因此,操作系統(tǒng)引入了比進程粒度更小的線程,作為并發(fā)執(zhí)行的基本單位,從而減少程序在并發(fā)執(zhí)行時所付出的時空開銷,提高并發(fā)性。和進程相比,線程的優(yōu)勢如下:
從資源上來講,線程是一種非常"節(jié)儉"的多任務操作方式。在linux系統(tǒng)下,啟動一個新的進程必須分配給它獨立的地址空間,建立眾多的數(shù)據(jù)表來維護它的代碼段、堆棧段和數(shù)據(jù)段,這是一種"昂貴"的多任務工作方式。
從切換效率上來講,運行于一個進程中的多個線程,它們之間使用相同的地址空間,而且線程間彼此切換所需時間也遠遠小于進程間切換所需要的時間。據(jù)統(tǒng)計,一個進程的開銷大約是一個線程開銷的30倍左右。(
從通信機制上來講,線程間方便的通信機制。對不同進程來說,它們具有獨立的數(shù)據(jù)空間,要進行數(shù)據(jù)的傳遞只能通過進程間通信的方式進行,這種方式不僅費時,而且很不方便。線程則不然,由于同一進程下的線程之間共享數(shù)據(jù)空間,所以一個線程的數(shù)據(jù)可以直接為其他線程所用,這不僅快捷,而且方便。
除以上優(yōu)點外,多線程程序作為一種多任務、并發(fā)的工作方式,還有如下優(yōu)點:
1、使多CPU系統(tǒng)更加有效。操作系統(tǒng)會保證當線程數(shù)不大于CPU數(shù)目時,不同的線程運行于不同的CPU上。
2、改善程序結構。一個既長又復雜的進程可以考慮分為多個線程,成為幾個獨立或半獨立的運行部分,這樣的程序才會利于理解和修改。
?
?
多線程和多進程的不同
進程是資源分配的最小單位,而線程時CPU調度的最小單位。多線程之間共享同一個進程的地址空間,線程間通信簡單,同步復雜,線程創(chuàng)建、銷毀和切換簡單,速度快,占用內存少,適用于多核分布式系統(tǒng),但是線程間會相互影響,一個線程意外終止會導致同一個進程的其他線程也終止,程序可靠性弱。而多進程間擁有各自獨立的運行地址空間,進程間不會相互影響,程序可靠性強,但是進程創(chuàng)建、銷毀和切換復雜,速度慢,占用內存多,進程間通信復雜,但是同步簡單,適用于多核、多機分布。多進程和多線程的使用場景?
多進程模型的優(yōu)勢是CPU
多線程模型主要優(yōu)勢為線程間切換代價較小,因此適用于I/O密集型的工作場景,因此I/O密集型的工作場景經(jīng)常會由于I/O阻塞導致頻繁的切換線程。同時,多線程模型也適用于單機多核分布式場景。
?
多進程模型,適用于CPU密集型。同時,多進程模型也適用于多機分布式場景中,易于多機擴展。
?
?
死鎖發(fā)生的條件以及如何解決死鎖
死鎖是指兩個或兩個以上進程在執(zhí)行過程中,因爭奪資源而造成的相互等待的現(xiàn)象。死鎖發(fā)生的四個必要條件如下:
互斥條件:進程對所分配到的資源不允許其他進程訪問,若其他進程訪問該資源,只能等待,直至占有該資源的進程使用完成后釋放該資源;
請求和保持條件:進程獲得一定的資源后,又對其他資源發(fā)出請求,但是該資源可能被其他進程占有,此時請求阻塞,但該進程不會釋放自己已經(jīng)占有的資源
不可剝奪條件:進程已獲得的資源,在未完成使用之前,不可被剝奪,只能在使用后自己釋放
環(huán)路等待條件:進程發(fā)生死鎖后,必然存在一個進程-資源之間的環(huán)形鏈
解決死鎖的方法即破壞上述四個條件之一,主要方法如下:
資源一次性分配,從而剝奪請求和保持條件
可剝奪資源:即當進程新的資源未得到滿足時,釋放已占有的資源,從而破壞不可剝奪的條件
資源有序分配法:系統(tǒng)給每類資源賦予一個序號,每個進程按編號遞增的請求資源,釋放則相反,從而破壞環(huán)路等待的條件
?
?
互斥鎖(mutex)機制,以及互斥鎖和讀寫鎖的區(qū)別
1、互斥鎖和讀寫鎖區(qū)別:
互斥鎖:mutex,用于保證在任何時刻,都只能有一個線程訪問該對象。當獲取鎖操作失敗時,線程會進入睡眠,等待鎖釋放時被喚醒。
讀寫鎖:rwlock,分為讀鎖和寫鎖。處于讀操作時,可以允許多個線程同時獲得讀操作。但是同一時刻只能有一個線程可以獲得寫鎖。其它獲取寫鎖失敗的線程都會進入睡眠狀態(tài),直到寫鎖釋放時被喚醒。?注意:寫鎖會阻塞其它讀寫鎖。當有一個線程獲得寫鎖在寫時,讀鎖也不能被其它線程獲取;寫者優(yōu)先于讀者(一旦有寫者,則后續(xù)讀者必須等待,喚醒時優(yōu)先考慮寫者)。適用于讀取數(shù)據(jù)的頻率遠遠大于寫數(shù)據(jù)的頻率的場合。
互斥鎖和讀寫鎖的區(qū)別:
1)讀寫鎖區(qū)分讀者和寫者,而互斥鎖不區(qū)分
2)互斥鎖同一時間只允許一個線程訪問該對象,無論讀寫;讀寫鎖同一時間內只允許一個寫者,但是允許多個讀者同時讀對象。
2、Linux的4種鎖機制:
互斥鎖:mutex,用于保證在任何時刻,都只能有一個線程訪問該對象。當獲取鎖操作失敗時,線程會進入睡眠,等待鎖釋放時被喚醒
讀寫鎖:rwlock,分為讀鎖和寫鎖。處于讀操作時,可以允許多個線程同時獲得讀操作。但是同一時刻只能有一個線程可以獲得寫鎖。其它獲取寫鎖失敗的線程都會進入睡眠狀態(tài),直到寫鎖釋放時被喚醒。 注意:寫鎖會阻塞其它讀寫鎖。當有一個線程獲得寫鎖在寫時,讀鎖也不能被其它線程獲取;寫者優(yōu)先于讀者(一旦有寫者,則后續(xù)讀者必須等待,喚醒時優(yōu)先考慮寫者)。適用于讀取數(shù)據(jù)的頻率遠遠大于寫數(shù)據(jù)的頻率的場合。
自旋鎖:spinlock,在任何時刻同樣只能有一個線程訪問對象。但是當獲取鎖操作失敗時,不會進入睡眠,而是會在原地自旋,直到鎖被釋放。這樣節(jié)省了線程從睡眠狀態(tài)到被喚醒期間的消耗,在加鎖時間短暫的環(huán)境下會極大的提高效率。但如果加鎖時間過長,則會非常浪費CPU資源。
RCU:即read-copy-update,在修改數(shù)據(jù)時,首先需要讀取數(shù)據(jù),然后生成一個副本,對副本進行修改。修改完成后,再將老數(shù)據(jù)update成新的數(shù)據(jù)。使用RCU時,讀者幾乎不需要同步開銷,既不需要獲得鎖,也不使用原子指令,不會導致鎖競爭,因此就不用考慮死鎖問題了。而對于寫者的同步開銷較大,它需要復制被修改的數(shù)據(jù),還必須使用鎖機制同步并行其它寫者的修改操作。在有大量讀操作,少量寫操作的情況下效率非常高。
?
?
A* a = new A; a->i = 10;在內核中的內存分配上發(fā)生了什么?
1、程序內存管理:
一個程序本質上都是由BSS段、data段、text段三個組成的。可以看到一個可執(zhí)行程序在存儲(沒有調入內存)時分為代碼段、數(shù)據(jù)區(qū)和未初始化數(shù)據(jù)區(qū)三部分。
BSS段(未初始化數(shù)據(jù)區(qū)):通常用來存放程序中未初始化的全局變量和靜態(tài)變量的一塊內存區(qū)域。BSS段屬于靜態(tài)分配,程序結束后靜態(tài)變量資源由系統(tǒng)自動釋放。
數(shù)據(jù)段:存放程序中已初始化的全局變量的一塊內存區(qū)域。數(shù)據(jù)段也屬于靜態(tài)內存分配
?
代碼段:存放程序執(zhí)行代碼的一塊內存區(qū)域。這部分區(qū)域的大小在程序運行前就已經(jīng)確定,并且內存區(qū)域屬于只讀。在代碼段中,也有可能包含一些只讀的常數(shù)變量
?
text段和data段在編譯時已經(jīng)分配了空間,而BSS段并不占用可執(zhí)行文件的大小,它是由鏈接器來獲取內存的。
?
bss段(未進行初始化的數(shù)據(jù))的內容并不存放在磁盤上的程序文件中。其原因是內核在程序開始運行前將它們設置為0。需要存放在程序文件中的只有正文段和初始化數(shù)據(jù)段。
?
data段(已經(jīng)初始化的數(shù)據(jù))則為數(shù)據(jù)分配空間,數(shù)據(jù)保存到目標文件中。
?
數(shù)據(jù)段包含經(jīng)過初始化的全局變量以及它們的值。BSS段的大小從可執(zhí)行文件中得到,然后鏈接器得到這個大小的內存塊,緊跟在數(shù)據(jù)段的后面。當這個內存進入程序的地址空間后全部清零。包含數(shù)據(jù)段和BSS段的整個區(qū)段此時通常稱為數(shù)據(jù)區(qū)。
?
可執(zhí)行程序在運行時又多出兩個區(qū)域:棧區(qū)和堆區(qū)。
?
棧區(qū):由編譯器自動釋放,存放函數(shù)的參數(shù)值、局部變量等。每當一個函數(shù)被調用時,該函數(shù)的返回類型和一些調用的信息被存放到棧中。然后這個被調用的函數(shù)再為他的自動變量和臨時變量在棧上分配空間。每調用一個函數(shù)一個新的棧就會被使用。棧區(qū)是從高地址位向低地址位增長的,是一塊連續(xù)的內存區(qū)域,最大容量是由系統(tǒng)預先定義好的,申請的棧空間超過這個界限時會提示溢出,用戶能從棧中獲取的空間較小。
?
堆區(qū):用于動態(tài)分配內存,位于BSS和棧中間的地址區(qū)域。由程序員申請分配和釋放。堆是從低地址位向高地址位增長,采用鏈式存儲結構。頻繁的 malloc/free造成內存空間的不連續(xù),產(chǎn)生碎片。當申請堆空間時庫函數(shù)是按照一定的算法搜索可用的足夠大的空間。因此堆的效率比棧要低的多。
2、A* a = new A; a->i = 10:
1)A *a:a是一個局部變量,類型為指針,故而操作系統(tǒng)在程序棧區(qū)開辟4/8字節(jié)的空間(0x000m),分配給指針a。
2)new A:通過new動態(tài)的在堆區(qū)申請類A大小的空間(0x000n)。
3)a = new A:將指針a的內存區(qū)域填入棧中類A申請到的地址的地址。即*(0x000m)=0x000n。
4)a->i:先找到指針a的地址0x000m,通過a的值0x000n和i在類a中偏移offset,得到a->i的地址0x000n + offset,進行*(0x000n + offset) = 10的賦值操作,即內存0x000n + offset的值是10。
?
?
一個類,里面有static,virtual,之類的,來說一說這個類的內存分布?
1、static修飾符
1)static修飾成員變量
對于非靜態(tài)數(shù)據(jù)成員,每個類對象都有自己的拷貝。而靜態(tài)數(shù)據(jù)成員被當做是類的成員,無論這個類被定義了多少個,靜態(tài)數(shù)據(jù)成員都只有一份拷貝,為該類型的所有對象所共享(包括其派生類)。所以,靜態(tài)數(shù)據(jù)成員的值對每個對象都是一樣的,它的值可以更新。
因為靜態(tài)數(shù)據(jù)成員在全局數(shù)據(jù)區(qū)分配內存,屬于本類的所有對象共享,所以它不屬于特定的類對象,在沒有產(chǎn)生類對象前就可以使用。
2)static修飾成員函數(shù)
與普通的成員函數(shù)相比,靜態(tài)成員函數(shù)由于不是與任何的對象相聯(lián)系,因此它不具有this指針。從這個意義上來說,它無法訪問屬于類對象的非靜態(tài)數(shù)據(jù)成員,也無法訪問非靜態(tài)成員函數(shù),只能調用其他的靜態(tài)成員函數(shù)。
Static修飾的成員函數(shù),在代碼區(qū)分配內存。
2、C++繼承和虛函數(shù)
C++多態(tài)分為靜態(tài)多態(tài)和動態(tài)多態(tài)。靜態(tài)多態(tài)是通過重載和模板技術實現(xiàn),在編譯的時候確定。動態(tài)多態(tài)通過虛函數(shù)和繼承關系來實現(xiàn),執(zhí)行動態(tài)綁定,在運行的時候確定。
動態(tài)多態(tài)實現(xiàn)有幾個條件:
(1)?虛函數(shù);
(2)?一個基類的指針或引用指向派生類的對象;
基類指針在調用成員函數(shù)(虛函數(shù))時,就會去查找該對象的虛函數(shù)表。虛函數(shù)表的地址在每個對象的首地址。查找該虛函數(shù)表中該函數(shù)的指針進行調用。
每個對象中保存的只是一個虛函數(shù)表的指針,C++內部為每一個類維持一個虛函數(shù)表,該類的對象的都指向這同一個虛函數(shù)表。
虛函數(shù)表中為什么就能準確查找相應的函數(shù)指針呢?因為在類設計的時候,虛函數(shù)表直接從基類也繼承過來,如果覆蓋了其中的某個虛函數(shù),那么虛函數(shù)表的指針就會被替換,因此可以根據(jù)指針準確找到該調用哪個函數(shù)。
3、virtual修飾符
如果一個類是局部變量則該類數(shù)據(jù)存儲在棧區(qū),如果一個類是通過new/malloc動態(tài)申請的,則該類數(shù)據(jù)存儲在堆區(qū)。
如果該類是virutal繼承而來的子類,則該類的虛函數(shù)表指針和該類其他成員一起存儲。虛函數(shù)表指針指向只讀數(shù)據(jù)段中的類虛函數(shù)表,虛函數(shù)表中存放著一個個函數(shù)指針,函數(shù)指針指向代碼段中的具體函數(shù)。
如果類中成員是virtual屬性,會隱藏父類對應的屬性。
?
?
軟鏈接和硬鏈接區(qū)別
為了解決文件共享問題,Linux引入了軟鏈接和硬鏈接。除了為Linux解決文件共享使用,還帶來了隱藏文件路徑、增加權限安全及節(jié)省存儲等好處。若1個inode號對應多個文件名,則為硬鏈接,即硬鏈接就是同一個文件使用了不同的別名,使用ln創(chuàng)建。若文件用戶數(shù)據(jù)塊中存放的內容是另一個文件的路徑名指向,則該文件是軟連接。軟連接是一個普通文件,有自己獨立的inode,但是其數(shù)據(jù)塊內容比較特殊。
?
?
用戶態(tài)和內核態(tài)區(qū)別
用戶態(tài)和內核態(tài)是操作系統(tǒng)的兩種運行級別,兩者最大的區(qū)別就是特權級不同。用戶態(tài)擁有最低的特權級,內核態(tài)擁有較高的特權級。運行在用戶態(tài)的程序不能直接訪問操作系統(tǒng)內核數(shù)據(jù)結構和程序。內核態(tài)和用戶態(tài)之間的轉換方式主要包括:系統(tǒng)調用,異常和中斷。協(xié)程
協(xié)程是一種用戶態(tài)的輕量級線程,協(xié)程的調度完全由用戶控制。從技術的角度來說,“協(xié)程就是你可以暫停執(zhí)行的函數(shù)”。協(xié)程擁有自己的寄存器上下文和棧。協(xié)程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操作棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變量,所以上下文的切換非常快。
協(xié)程和進程線程的區(qū)別
1) 一個線程可以多個協(xié)程,一個進程也可以單獨擁有多個協(xié)程。
2) 線程進程都是同步機制,而協(xié)程則是異步。
3)?協(xié)程能保留上一次調用時的狀態(tài),每次過程重入時,就相當于進入上一次調用的狀態(tài)。
4)線程是搶占式,而協(xié)程是非搶占式的,所以需要用戶自己釋放使用權來切換到其他協(xié)程,因此同一時間其實只有一個協(xié)程擁有運行權,相當于單線程的能力。
5)協(xié)程并不是取代線程, 而且抽象于線程之上, 線程是被分割的CPU資源, 協(xié)程是組織好的代碼流程, 協(xié)程需要線程來承載運行, 線程是協(xié)程的資源, 但協(xié)程不會直接使用線程, 協(xié)程直接利用的是執(zhí)行器(Interceptor), 執(zhí)行器可以關聯(lián)任意線程或線程池, 可以使當前線程, UI線程, 或新建新程.。
6)線程是協(xié)程的資源。協(xié)程通過Interceptor來間接使用線程這個資源。
?
?IO多路復用(IO multiplexing)
?IO multiplexing這個詞可能有點陌生,但是如果我說select/epoll,大概就都能明白了。有些地方也稱這種IO方式為事件驅動IO(event driven IO)。我們都知道,select/epoll的好處就在于單個process就可以同時處理多個網(wǎng)絡連接的IO。它的基本原理就是select/epoll這個function會不斷的輪詢所負責的所有socket,當某個socket有數(shù)據(jù)到達了,就通知用戶進程。它的流程如圖:?
當用戶進程調用了select,那么整個進程會被block,而同時,kernel會“監(jiān)視”所有select負責的socket,當任何一個socket中的數(shù)據(jù)準備好了,select就會返回。這個時候用戶進程再調用read操作,將數(shù)據(jù)從kernel拷貝到用戶進程。
??? 這個圖和blocking IO的圖其實并沒有太大的不同,事實上還更差一些。因為這里需要使用兩個系統(tǒng)調用(select和recvfrom),而blocking IO只調用了一個系統(tǒng)調用(recvfrom)。但是,用select的優(yōu)勢在于它可以同時處理多個connection。
? ? 強調:
? ? 1. 如果處理的連接數(shù)不是很高的話,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延遲還更大。select/epoll的優(yōu)勢并不是對于單個連接能處理得更快,而是在于能處理更多的連接。
? ? 2.?在多路復用模型中,對于每一個socket,一般都設置成為non-blocking,但是,如上圖所示,整個用戶的process其實是一直被block的。只不過process是被select這個函數(shù)block,而不是被socket IO給block。
? ??結論: select的優(yōu)勢在于可以處理多個連接,不適用于單個連接?
?
?
?
(1)select==>時間復雜度O(n)
它僅僅知道了,有I/O事件發(fā)生了,卻并不知道是哪那幾個流(可能有一個,多個,甚至全部),我們只能無差別輪詢所有流,找出能讀出數(shù)據(jù),或者寫入數(shù)據(jù)的流,對他們進行操作。所以select具有O(n)的無差別輪詢復雜度,同時處理的流越多,無差別輪詢時間就越長。
(2)poll==>時間復雜度O(n)
poll本質上和select沒有區(qū)別,它將用戶傳入的數(shù)組拷貝到內核空間,然后查詢每個fd對應的設備狀態(tài),?但是它沒有最大連接數(shù)的限制,原因是它是基于鏈表來存儲的.
(3)epoll==>時間復雜度O(1)
epoll可以理解為event poll,不同于忙輪詢和無差別輪詢,epoll會把哪個流發(fā)生了怎樣的I/O事件通知我們。所以我們說epoll實際上是事件驅動(每個事件關聯(lián)上fd)的,此時我們對這些流的操作都是有意義的。(復雜度降低到了O(1))
?
?int epoll_create(int size);?
?int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);?
?int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);?
?
epoll的高效就在于,當我們調用epoll_ctl往里塞入百萬個句柄時,epoll_wait仍然可以飛快的返回,并有效的將發(fā)生事件的句柄給我們用戶。這是由于我們在調用epoll_create時,內核除了幫我們在epoll文件系統(tǒng)里建了個file結點,在內核cache里建了個紅黑樹用于存儲以后epoll_ctl傳來的socket外,還會再建立一個list鏈表,用于存儲準備就緒的事件,當epoll_wait調用時,僅僅觀察這個list鏈表里有沒有數(shù)據(jù)即可。有數(shù)據(jù)就返回,沒有數(shù)據(jù)就sleep,等到timeout時間到后即使鏈表沒數(shù)據(jù)也返回。所以,epoll_wait非常高效。 那么,這個準備就緒list鏈表是怎么維護的呢?當我們執(zhí)行epoll_ctl時,除了把socket放到epoll文件系統(tǒng)里file對象對應的紅黑樹上之外,還會給內核中斷處理程序注冊一個回調函數(shù),告訴內核,如果這個句柄的中斷到了,就把它放到準備就緒list鏈表里。所以,當一個socket上有數(shù)據(jù)到了,內核在把網(wǎng)卡上的數(shù)據(jù)copy到內核中后就來把socket插入到準備就緒鏈表里了。 如此,一顆紅黑樹,一張準備就緒句柄鏈表,少量的內核cache,就幫我們解決了大并發(fā)下的socket處理問題。執(zhí)行epoll_create時,創(chuàng)建了紅黑樹和就緒鏈表,執(zhí)行epoll_ctl時,如果增加socket句柄,則檢查在紅黑樹中是否存在,存在立即返回,不存在則添加到樹干上,然后向內核注冊回調函數(shù),用于當中斷事件來臨時向準備就緒鏈表中插入數(shù)據(jù)。執(zhí)行epoll_wait時立刻返回準備就緒鏈表里的數(shù)據(jù)即可。
?
?
?
?
mmap
mmap是一種內存映射文件的方法,即將一個文件或者其它對象映射到進程的地址空間,實現(xiàn)文件磁盤地址和進程虛擬地址空間中一段虛擬地址的一一對映關系。實現(xiàn)這樣的映射關系后,進程就可以采用指針的方式讀寫操作這一段內存,而系統(tǒng)會自動回寫臟頁面到對應的文件磁盤上,即完成了對文件的操作而不必再調用read,write等系統(tǒng)調用函數(shù)。相反,內核空間對這段區(qū)域的修改也直接反映用戶空間,從而可以實現(xiàn)不同進程間的文件共享。如下圖所示:
?
占坑待補?
?
?
MD5應用
MD5的典型應用是對一段信息(Message)產(chǎn)生信息摘要(Message-Digest),以防止被篡改。
MD5將整個文件當作一個大文本信息,通過其不可逆的字符串變換算法,產(chǎn)生了這個唯一的MD5信息摘要。
MD5就可以為任何文件(不管其大小、格式、數(shù)量)產(chǎn)生一個同樣獨一無二的“數(shù)字指紋”,如果任何人對文件做了任何改動,其MD5值也就是對應的“數(shù)字指紋”都會發(fā)生變化。
MD5實際上是一種有損壓縮技術,壓縮前文件一樣MD5值一定一樣,反之MD5值一樣并不能保證壓縮前的數(shù)據(jù)是一樣的。在密碼學上發(fā)生這樣的概率是很小的,所以MD5在密碼加密領域有一席之地。但是專業(yè)的黑客甚至普通黑客也可以利用MD5值,實際是有損壓縮技術這一原理,將MD5的逆運算的值作為一張表俗稱彩虹表的散列表來破解密碼。
?
?
?
?
?
?
轉載于:https://www.cnblogs.com/DSKer/p/10932739.html
總結
以上是生活随笔為你收集整理的备战秋招——操作系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: configParser模块详谈
- 下一篇: 使用 ArcGIS Desktop 切瓦