操做系統常見面試題

1.進程的常見狀態?以及各類狀態之間的轉換條件?

  • 就緒:進程已處於準備好運行的狀態,即進程已分配到除CPU外的全部必要資源後,只要再得到CPU,即可當即執行。
  • 執行:進程已經得到CPU,程序正在執行狀態。
  • 阻塞:正在執行的進程因爲發生某事件(如I/O請求、申請緩衝區失敗等)暫時沒法繼續執行的狀態。

          

2.進程同步

進程同步的主要任務:是對多個相關進程在執行次序上進行協調,以使併發執行的諸進程之間能有效地共享資源和相互合做,從而使程序的執行具備可再現性。html

  同步機制遵循的原則:linux

  (1)空閒讓進;c++

  (2)忙則等待(保證對臨界區的互斥訪問);程序員

  (3)有限等待(有限表明有限的時間,避免死等);web

  (4)讓權等待,(當進程不能進入本身的臨界區時,應該釋放處理機,以避免陷入忙等狀態)。算法

3.進程的通訊方式有哪些?

  進程通訊,是指進程之間的信息交換(信息量少則一個狀態或數值,多者則是成千上萬個字節)。所以,對於用信號量進行的進程間的互斥和同步,因爲其所交換的信息量少而被歸結爲低級通訊。windows

  所謂高級進程通訊指:用戶能夠利用操做系統所提供的一組通訊命令傳送大量數據的一種通訊方式。操做系統隱藏了進程通訊的實現細節。或者說,通訊過程對用戶是透明的。數組

  高級通訊機制可歸結爲三大類:緩存

  (1)共享存儲器系統(存儲器中劃分的共享存儲區);實際操做中對應的是「剪貼板」(剪貼板其實是系統維護管理的一塊內存區域)的通訊方式,好比舉例以下:word進程按下ctrl+c,在ppt進程按下ctrl+v,即完成了word進程和ppt進程之間的通訊,複製時將數據放入到剪貼板,粘貼時從剪貼板中取出數據,而後顯示在ppt窗口上。安全

  (2)消息傳遞系統(進程間的數據交換以消息(message)爲單位,當今最流行的微內核操做系統中,微內核與服務器之間的通訊,無一例外地都採用了消息傳遞機制。應用舉例:郵槽(MailSlot)是基於廣播通訊體系設計出來的,它採用無鏈接的不可靠的數據傳輸。郵槽是一種單向通訊機制,建立郵槽的服務器進程讀取數據,打開郵槽的客戶機進程寫入數據。

  (3)管道通訊系統(管道即:鏈接讀寫進程以實現他們之間通訊的共享文件(pipe文件,相似先進先出的隊列,由一個進程寫,另外一進程讀))。實際操做中,管道分爲:匿名管道、命名管道。匿名管道是一個未命名的、單向管道,經過父進程和一個子進程之間傳輸數據。匿名管道只能實現本地機器上兩個進程之間的通訊,而不能實現跨網絡的通訊。命名管道不只能夠在本機上實現兩個進程間的通訊,還能夠跨網絡實現兩個進程間的通訊。

  • 管道管道是單向的、先進先出的、無結構的、固定大小的字節流,它把一個進程的標準輸出和另外一個進程的標準輸入鏈接在一塊兒。寫進程在管道的尾端寫入數據,讀進程在管道的道端讀出數據。數據讀出後將從管道中移走,其它讀進程都不能再讀到這些數據。管道提供了簡單的流控制機制。進程試圖讀空管道時,在有數據寫入管道前,進程將一直阻塞。一樣地,管道已經滿時,進程再試圖寫管道,在其它進程從管道中移走數據以前,寫進程將一直阻塞。

          注1:無名管道只能實現父子或者兄弟進程之間的通訊,有名管道(FIFO)能夠實現互不相關的兩個進程之間的通訊。

     注2:用FIFO讓一個服務器和多個客戶端進行交流時候,每一個客戶在向服務器發送信息前創建本身的讀管道,或者讓服務器在獲得數據後再創建管道。使用客戶的進程號(pid)做爲管道名是一種經常使用的方法。客戶能夠先把本身的進程號告訴服務器,而後再到那個以本身進程號命名的管道中讀取回復。

  • 信號量信號量是一個計數器,能夠用來控制多個進程對共享資源的訪問。它常做爲一種鎖機制,防止某進程正在訪問共享資源時,其它進程也訪問該資源。所以,主要做爲進程間以及同一進程內不一樣線程之間的同步手段。

  • 消息隊列是一個在系統內核中用來保存消  息的隊列,它在系統內核中是以消息鏈表的形式出現的。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩衝區大小受限等缺點

  • 共享內存:共享內存容許兩個或多個進程訪問同一個邏輯內存。這一段內存能夠被兩個或兩個以上的進程映射至自身的地址空間中,一個進程寫入共享內存的信息,能夠被其餘使用這個共享內存的進程,經過一個簡單的內存讀取讀出,從而實現了進程間的通訊。若是某個進程向共享內存寫入數據,所作的改動將當即影響到能夠訪問同一段共享內存的任何其餘進程。共享內存是最快的IPC方式,它是針對其它進程間通訊方式運行效率低而專門設計的。它每每與其它通訊機制(如信號量)配合使用,來實現進程間的同步和通訊。

  • 套接字:套接字也是一種進程間通訊機制,與其它通訊機制不一樣的是,它可用於不一樣機器間的進程通訊。

4.上下文切換

對於單核單線程CPU而言,在某一時刻只能執行一條CPU指令。上下文切換(Context Switch)是一種將CPU資源從一個進程分配給另外一個進程的機制。從用戶角度看,計算機可以並行運行多個進程,這偏偏是操做系統經過快速上下文切換形成的結果。在切換的過程當中,操做系統須要先存儲當前進程的狀態(包括內存空間的指針,當前執行完的指令等等),再讀入下一個進程的狀態,而後執行此進程。

5.進程與線程的區別和聯繫?

  • 進程是具備必定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。
  • 線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。

進程和線程的關係

(1)一個線程只能屬於一個進程,而一個進程能夠有多個線程,但至少有一個線程。線程是操做系統可識別的最小執行和調度單位。

(2)資源分配給進程,同一進程的全部線程共享該進程的全部資源。 同一進程中的多個線程共享代碼段(代碼和常量),數據段(全局變量和靜態變量),擴展段(堆存儲)。可是每一個線程擁有本身的棧段,棧段又叫運行時段,用來存放全部局部變量和臨時變量。

(3)處理機分給線程,即真正在處理機上運行的是線程。

(4)線程在執行過程當中,須要協做同步。不一樣進程的線程間要利用消息通訊的辦法實現同步。

進程與線程的區別?

(1)進程有本身的獨立地址空間,線程沒有

(2)進程是資源分配的最小單位,線程是CPU調度的最小單位

(3)進程和線程通訊方式不一樣(線程之間的通訊比較方便。同一進程下的線程共享數據(好比全局變量,靜態變量),經過這些數據來通訊不只快捷並且方便,固然如何處理好這些訪問的同步與互斥正是編寫多線程程序的難點。而進程之間的通訊只能經過進程通訊的方式進行。)

(4)進程上下文切換開銷大,線程開銷小

(5)一個進程掛掉了不會影響其餘進程,而線程掛掉了會影響其餘線程

(6)對進程進程操做通常開銷都比較大,對線程開銷就小了 

 爲何進程上下文切換比線程上下文切換代價高?

進程切換分兩步:

1.切換頁目錄以使用新的地址空間

2.切換內核棧和硬件上下文

對於linux來講,線程和進程的最大區別就在於地址空間,對於線程切換,第1步是不須要作的,第2是進程和線程切換都要作的。

切換的性能消耗:

一、線程上下文切換和進程上下問切換一個最主要的區別是線程的切換虛擬內存空間依然是相同的,可是進程切換是不一樣的。這兩種上下文切換的處理都是經過操做系統內核來完成的。內核的這種切換過程伴隨的最顯著的性能損耗是將寄存器中的內容切換出。

二、另一個隱藏的損耗是上下文的切換會擾亂處理器的緩存機制。簡單的說,一旦去切換上下文,處理器中全部已經緩存的內存地址一瞬間都做廢了。還有一個顯著的區別是當你改變虛擬內存空間的時候,處理的頁表緩衝(processor's Translation Lookaside Buffer (TLB))或者至關的神馬東西會被所有刷新,這將致使內存的訪問在一段時間內至關的低效。可是在線程的切換中,不會出現這個問題。

 

轉自知乎:進程和線程的區別

連接:https://www.zhihu.com/question/25532384/answer/81152571

首先來一句歸納的總論:進程和線程都是一個時間段的描述,是CPU工做時間段的描述。

下面細說背景
CPU+RAM+各類資源(好比顯卡,光驅,鍵盤,GPS, 等等外設)構成咱們的電腦,可是電腦的運行,實際就是CPU和相關寄存器以及RAM之間的事情。

一個最最基礎的事實:CPU太快,太快,太快了,寄存器僅僅可以追的上他的腳步,RAM和別的掛在各總線上的設備徹底是望其項背。那當多個任務要執行的時候怎麼辦呢?輪流着來?或者誰優先級高誰來?無論怎麼樣的策略,一句話就是在CPU看來就是輪流着來。

一個必須知道的事實:執行一段程序代碼,實現一個功能的過程介紹 ,當獲得CPU的時候,相關的資源必須也已經就位,就是顯卡啊,GPS啊什麼的必須就位,而後CPU開始執行。這裏除了CPU之外全部的就構成了這個程序的執行環境,也就是咱們所定義的程序上下文。當這個程序執行完了,或者分配給他的CPU執行時間用完了,那它就要被切換出去,等待下一次CPU的臨幸。在被切換出去的最後一步工做就是保存程序上下文,由於這個是下次他被CPU臨幸的運行環境,必須保存。

串聯起來的事實:前面講過在CPU看來全部的任務都是一個一個的輪流執行的,具體的輪流方法就是: 先加載程序A的上下文,而後開始執行A,保存程序A的上下文,調入下一個要執行的程序B的程序上下文,而後開始執行B,保存程序B的上下文。。。

========= 重要的東西出現了========
進程和線程 就是這樣的背景出來的 ,兩個名詞不過是對應的CPU時間段的描述,名詞就是這樣的功能。
  • 進程就是包換上下文切換的程序執行時間總和 = CPU加載上下文+CPU執行+CPU保存上下文

線程是什麼呢?
進程的顆粒度太大,每次都要有上下的調入,保存,調出。若是咱們把進程比喻爲一個運行在電腦上的軟件,那麼一個軟件的執行不多是一條邏輯執行的,一定有多個分支和多個程序段,就比如要實現程序A,實際分紅 a,b,c等多個塊組合而成。那麼這裏具體的執行就可能變成:

程序A獲得CPU =》CPU加載上下文,開始執行程序A的a小段,而後執行A的b小段,而後再執行A的c小段,最後CPU保存A的上下文。

這裏a,b,c的執行是共享了A的上下文,CPU在執行的時候沒有進行上下文切換的。這 裏的a,b,c就是線程,也就是說線程是共享了進程的上下文環境,的更爲細小的CPU時間段。

到此全文結束,再一個總結:

進程和線程都是一個時間段的描述,是CPU工做時間段的描述,不過是顆粒大小不一樣。
 
  • 進程(process)與線程(thread)最大的區別是進程擁有本身的地址空間,某進程內的線程對於其餘進程不可見,即進程A不能經過傳地址的方式直接讀寫進程B的存儲區域。進程之間的通訊須要經過進程間通訊(Inter-process communication,IPC)。與之相對的,同一進程的各線程間之間能夠直接經過傳遞地址或全局變量的方式傳遞信息

  • 進程做爲操做系統中擁有資源和獨立調度的基本單位,能夠擁有多個線程。一般操做系統中運行的一個程序就對應一個進程。在同一進程中,線程的切換不會引發進程切換。在不一樣進程中進行線程切換,如從一個進程內的線程切換到另外一個進程中的線程時,會引發進程切換。相比進程切換,線程切換的開銷要小不少。線程於進程相互結合可以提升系統的運行效率。

線程能夠分爲兩類:

  • 用戶級線程(user level thread):對於這類線程,有關線程管理的全部工做都由應用程序完成,內核意識不到線程的存在。在應用程序啓動後,操做系統分配給該程序一個進程號,以及其對應的內存空間等資源。應用程序一般先在一個線程中運行,該線程被成爲主線程。在其運行的某個時刻,能夠經過調用線程庫中的函數建立一個在相同進程中運行的新線程。用戶級線程的好處是很是高效,不須要進入內核空間,但併發效率不高。

  • 內核級線程(kernel level thread):對於這類線程,有關線程管理的全部工做由內核完成,應用程序沒有進行線程管理的代碼,只能調用內核線程的接口。內核維護進程及其內部的每一個線程,調度也由內核基於線程架構完成。內核級線程的好處是,內核能夠將不一樣線程更好地分配到不一樣的CPU,以實現真正的並行計算。

事實上,在現代操做系統中,每每使用組合方式實現多線程,即線程建立徹底在用戶空間中完成,而且一個應用程序中的多個用戶級線程被映射到一些內核級線程上,至關因而一種折中方案。


6.進程調度

調度種類

  • 高級調度:(High-Level Scheduling)又稱爲做業調度,它決定把後備做業調入內存運行;

  • 低級調度:(Low-Level Scheduling)又稱爲進程調度,它決定把就緒隊列的某進程得到CPU;

  • 中級調度:(Intermediate-Level Scheduling)又稱爲在虛擬存儲器中引入,在內、外存對換區進行進程對換。

非搶佔式調度與搶佔式調度

  • 非搶佔式:分派程序一旦把處理機分配給某進程後便讓它一直運行下去,直到進程完成或發生進程調度進程調度某事件而阻塞時,才把處理機分配給另外一個進程。

  • 搶佔式:操做系統將正在運行的進程強行暫停,由調度程序將CPU分配給其餘就緒進程的調度方式。

調度策略的設計

  • 響應時間: 從用戶輸入到產生反應的時間

  • 週轉時間: 從任務開始到任務結束的時間

CPU任務能夠分爲交互式任務批處理任務,調度最終的目標是合理的使用CPU,使得交互式任務的響應時間儘量短,用戶不至於感到延遲,同時使得批處理任務的週轉時間儘量短,減小用戶等待的時間。

調度算法:

FIFO或First Come, First Served (FCFS)先來先服務

  • 調度的順序就是任務到達就緒隊列的順序。

  • 公平、簡單(FIFO隊列)、非搶佔、不適合交互式。

  • 未考慮任務特性,平均等待時間能夠縮短。

Shortest Job First (SJF)

  • 最短的做業(CPU區間長度最小)最早調度。

  • SJF能夠保證最小的平均等待時間。

Shortest Remaining Job First (SRJF)

  • SJF的可搶佔版本,比SJF更有優點。

  • SJF(SRJF): 如何知道下一CPU區間大小?根據歷史進行預測: 指數平均法。

優先權調度

  • 每一個任務關聯一個優先權,調度優先權最高的任務。

  • 注意:優先權過低的任務一直就緒,得不到運行,出現「飢餓」現象。

Round-Robin(RR)輪轉調度算法

  • 設置一個時間片,按時間片來輪轉調度(「輪叫」算法)

  • 優勢: 定時有響應,等待時間較短;缺點: 上下文切換次數較多;

  • 時間片太大,響應時間太長;吞吐量變小,週轉時間變長;當時間片過長時,退化爲FCFS。

多級隊列調度

  • 按照必定的規則創建多個進程隊列

  • 不一樣的隊列有固定的優先級(高優先級有搶佔權)

  • 不一樣的隊列能夠給不一樣的時間片和採用不一樣的調度方法

  • 存在問題1:無法區分I/O bound和CPU bound;

  • 存在問題2:也存在必定程度的「飢餓」現象;

多級反饋隊列

  • 在多級隊列的基礎上,任務能夠在隊列之間移動,更細緻的區分任務。

  • 能夠根據「享用」CPU時間多少來移動隊列,阻止「飢餓」。

  • 最通用的調度算法,多數OS都使用該方法或其變形,如UNIX、Windows等。

多級反饋隊列調度算法描述:

clipboard.png

  • 進程在進入待調度的隊列等待時,首先進入優先級最高的Q1等待。

  • 首先調度優先級高的隊列中的進程。若高優先級中隊列中已沒有調度的進程,則調度次優先級隊列中的進程。例如:Q1,Q2,Q3三個隊列,只有在Q1中沒有進程等待時纔去調度Q2,同理,只有Q1,Q2都爲空時纔會去調度Q3。

  • 對於同一個隊列中的各個進程,按照時間片輪轉法調度。好比Q1隊列的時間片爲N,那麼Q1中的做業在經歷了N個時間片後若尚未完成,則進入Q2隊列等待,若Q2的時間片用完後做業還不能完成,一直進入下一級隊列,直至完成。

  • 在低優先級的隊列中的進程在運行時,又有新到達的做業,那麼在運行完這個時間片後,CPU立刻分配給新到達的做業(搶佔式)。

一個簡單的例子
假設系統中有3個反饋隊列Q1,Q2,Q3,時間片分別爲2,4,8。如今有3個做業J1,J2,J3分別在時間 0 ,1,3時刻到達。而它們所須要的CPU時間分別是3,2,1個時間片。

    • 時刻0 J1到達。 因而進入到隊列1 ,運行1個時間片 ,時間片還未到,此時J2到達。

    • 時刻1 J2到達。 因爲時間片仍然由J1掌控,因而等待。J1在運行了1個時間片後,已經完成了在Q1中的2個時間片的限制,因而J1置於Q2等待被調度。如今處理機分配給J2。

    • 時刻2 J1進入Q2等待調度,J2得到CPU開始運行。

    • 時刻3 J3到達,因爲J2的時間片未到,故J3在Q1等待調度,J1也在Q2等待調度。

    • 時刻4 J2處理完成,因爲J3,J1都在等待調度,可是J3所在的隊列比J1所在的隊列的優先級要高,因而J3被調度,J1繼續在Q2等待。

    • 時刻5 J3通過1個時間片,完成。

    • 時刻6 因爲Q1已經空閒,因而開始調度Q2中的做業,則J1獲得處理器開始運行。 J1再通過一個時間片,完成了任務。因而整個調度過程結束。

 7.死鎖的條件?以及如何處理死鎖問題?

定義:若是一組進程中的每個進程都在等待僅由該組進程中的其餘進程才能引起的事件,那麼該組進程就是死鎖的。或者在兩個或多個併發進程中,若是每一個進程持有某種資源而又都等待別的進程釋放它或它們如今保持着的資源,在未改變這種狀態以前都不能向前推動,稱這一組進程產生了死鎖。通俗地講,就是兩個或多個進程被無限期地阻塞、相互等待的一種狀態。

產生死鎖的必要條件:

  • 互斥條件(Mutual exclusion):資源不能被共享,只能由一個進程使用。

  • 請求與保持條件(Hold and wait):已經獲得資源的進程能夠再次申請新的資源。

  • 非搶佔條件(No pre-emption):已經分配的資源不能從相應的進程中被強制地剝奪。

  • 循環等待條件(Circular wait):系統中若干進程組成環路,該環路中每一個進程都在等待相鄰進程正佔用的資源。

如何處理死鎖問題:

  • 忽略該問題。例如鴕鳥算法,該算法能夠應用在極少發生死鎖的的狀況下。爲何叫鴕鳥算法呢,由於傳說中鴕鳥看到危險就把頭埋在地底下,可能鴕鳥以爲看不到危險也就沒危險了吧。跟掩耳盜鈴有點像。

  • 檢測死鎖而且恢復。

  • 仔細地對資源進行動態分配,使系統始終處於安全狀態以避免死鎖

  • 經過破除死鎖四個必要條件之一,來防止死鎖產生。

8.臨界資源

  • 在操做系統中,進程是佔有資源的最小單位(線程能夠訪問其所在進程內的全部資源,但線程自己並不佔有資源或僅僅佔有一點必須資源)。但對於某些資源來講,其在同一時間只能被一個進程所佔用。這些一次只能被一個進程所佔用的資源就是所謂的臨界資源。典型的臨界資源好比物理上的打印機,或是存在硬盤或內存中被多個進程所共享的一些變量和數據等(若是這類資源不被當作臨界資源加以保護,那麼頗有可能形成丟數據的問題)。

  • 對於臨界資源的訪問,必須是互斥進行。也就是當臨界資源被佔用時,另外一個申請臨界資源的進程會被阻塞,直到其所申請的臨界資源被釋放。而進程內訪問臨界資源的代碼被成爲臨界區。

9.一個程序從開始運行到結束的完整過程(四個過程)

一、預處理:條件編譯,頭文件包含,宏替換的處理,生成.i文件。

二、編譯:將預處理後的文件轉換成彙編語言,生成.s文件

三、彙編:彙編變爲目標代碼(機器代碼)生成.o的文件

四、連接:鏈接目標代碼,生成可執行程序

連接

10.內存池、進程池、線程池。(c++程序員必須掌握)

    首先介紹一個概念「池化技術 」。池化技術就是:提早保存大量的資源,以備不時之需以及重複使用。池化技術應用普遍,如內存池,線程池,鏈接池等等。內存池相關的內容,建議看看Apache、Nginx等開源web服務器的內存池實現。
    因爲在實際應用當作,分配內存、建立進程、線程都會設計到一些系統調用,系統調用須要致使程序從用戶態切換到內核態,是很是耗時的操做。所以,當程序中須要頻繁的進行內存申請釋放,進程、線程建立銷燬等操做時,一般會使用內存池、進程池、線程池技術來提高程序的性能。

    線程池:線程池的原理很簡單,相似於操做系統中的緩衝區的概念,它的流程以下:先啓動若干數量的線程,並讓這些線程都處於睡眠狀態,當須要一個開闢一個線程去作具體的工做時,就會喚醒線程池中的某一個睡眠線程,讓它去作具體工做,當工做完成後,線程又處於睡眠狀態,而不是將線程銷燬。

    進程池與線程池同理。

    內存池:內存池是指程序預先從操做系統申請一塊足夠大內存,此後,當程序中須要申請內存的時候,不是直接向操做系統申請,而是直接從內存池中獲取;同理,當程序釋放內存的時候,並不真正將內存返回給操做系統,而是返回內存池。當程序退出(或者特定時間)時,內存池纔將以前申請的內存真正釋放。

11.動態連接庫與靜態連接庫的區別

靜態庫

  • 靜態庫是一個外部函數與變量的集合體。靜態庫的文件內容,一般包含一堆程序員自定的變量與函數,其內容不像動態連接庫那麼複雜,在編譯期間由編譯器與連接器將它集成至應用程序內,並製做成目標文件以及能夠獨立運做的可執行文件。而這個可執行文件與編譯可執行文件的程序,都是一種程序的靜態建立(static build)。

動態庫

  • 靜態庫很方便,可是若是咱們只是想用庫中的某一個函數,卻仍然得把全部的內容都連接進去。一個更現代的方法則是使用共享庫,避免了在文件中靜態庫的大量重複。

  • 動態連接能夠在首次載入的時候執行(load-time linking),這是 Linux 的標準作法,會由動態連接器ld-linux.so 完成,比方標準 C 庫(libc.so) 一般就是動態連接的,這樣全部的程序能夠共享同一個庫,而不用分別進行封裝。

  • 動態連接也能夠在程序開始執行的時候完成(run-time linking),在 Linux 中使用 dlopen()接口來完成(會使用函數指針),一般用於分佈式軟件,高性能服務器上。並且共享庫也能夠在多個進程間共享。

  • 連接使得咱們能夠用多個對象文件構造咱們的程序。能夠在程序的不一樣階段進行(編譯、載入、運行期間都可),理解連接能夠幫助咱們避免遇到奇怪的錯誤

區別:

  1. 使用靜態庫的時候,靜態連接庫要參與編譯,在生成執行文件以前的連接過程當中,要將靜態連接庫的所有指令直接連接入可執行文件中。而動態庫提供了一種方法,使進程能夠調用不屬於其可執行代碼的函數。函數的可執行代碼位於一個.dll文件中,該dll包含一個或多個已被編譯,連接並與使用它們的進程分開儲存的函數。
  2. 靜態庫中不能再包含其餘動態庫或靜態庫,而在動態庫中還能夠再包含其餘動態或者靜態庫。
  3. 靜態庫在編譯的時候,就將庫函數裝在到程序中去了,而動態庫函數必須在運行的時候才被裝載,因此使用靜態庫速度快一些。

連接

12.虛擬內存?優缺點?

定義:具備請求調入功能和置換功能,能從邏輯上對內存容量加以擴充得一種存儲器系統。其邏輯容量由內存之和和外存之和決定。

與傳統存儲器比較虛擬存儲器有如下三個主要特徵:

  • 屢次性,是指無需在做業運行時一次性地所有裝入內存,而是容許被分紅屢次調入內存運行。
  • 對換性,是指無需在做業運行時一直常駐內存,而是容許在做業的運行過程當中,進行換進和換出。
  • 虛擬性,是指從邏輯上擴充內存的容量,使用戶所看到的內存容量,遠大於實際的內存容量。

虛擬內存的實現有如下兩種方式:

  • 請求分頁存儲管理。
  • 請求分段存儲管理。

13.頁面置換算法

操做系統將內存按照頁面進行管理,在須要的時候才把進程相應的部分調入內存。當產生缺頁中斷時,須要選擇一個頁面寫入。若是要換出的頁面在內存中被修改過,變成了「髒」頁面,那就須要先寫會到磁盤。頁面置換算法,就是要選出最合適的一個頁面,使得置換的效率最高。頁面置換算法有不少,簡單介紹幾個,重點介紹比較重要的LRU及其實現算法。

1、最優頁面置換算法

最理想的狀態下,咱們給頁面作個標記,挑選一個最遠纔會被再次用到的頁面調出。固然,這樣的算法不可能實現,由於不肯定一個頁面在什麼時候會被用到。

2、先進先出頁面置換算法(FIFO)及其改進

這種算法的思想和隊列是同樣的,該算法老是淘汰最早進入內存的頁面,即選擇在內存中駐留時間最久的頁面予淘汰。實現:把一個進程已調入內存的頁面按前後次序連接成一個隊列,而且設置一個指針老是指向最老的頁面。缺點:對於有些常常被訪問的頁面如含有全局變量、經常使用函數、例程等的頁面,不能保證這些不被淘汰。

3、最近最少使用頁面置換算法LRU(Least Recently Used)

根據頁面調入內存後的使用狀況作出決策。LRU置換算法是選擇最近最久未使用的頁面進行淘汰。

1.爲每一個在內存中的頁面配置一個移位寄存器。(P165)定時信號將每隔一段時間將寄存器右移一位。最小數值的寄存器對應頁面就是最久未使用頁面。

2.利用一個特殊的棧保存當前使用的各個頁面的頁面號。每當進程訪問某頁面時,便將該頁面的頁面號從棧中移出,將它壓入棧頂。所以,棧頂永遠是最新被訪問的頁面號,棧底是最近最久未被訪問的頁面號。

連接:分頁內存管理(把虛擬內存空間和物理內存空間均劃分爲大小相同的頁面等內容)

連接:分段內存管理

14.中斷與系統調用

所謂的中斷就是在計算機執行程序的過程當中,因爲出現了某些特殊事情,使得CPU暫停對程序的執行,轉而去執行處理這一事件的程序。等這些特殊事情處理完以後再回去執行以前的程序。中斷通常分爲三類:

  • 由計算機硬件異常或故障引發的中斷,稱爲內部異常中斷

  • 由程序中執行了引發中斷的指令而形成的中斷,稱爲軟中斷(這也是和咱們將要說明的系統調用相關的中斷);

  • 由外部設備請求引發的中斷,稱爲外部中斷。簡單來講,對中斷的理解就是對一些特殊事情的處理。

與中斷緊密相連的一個概念就是中斷處理程序了。當中斷髮生的時候,系統須要去對中斷進行處理,對這些中斷的處理是由操做系統內核中的特定函數進行的,這些處理中斷的特定的函數就是咱們所說的中斷處理程序了。

另外一個與中斷緊密相連的概念就是中斷的優先級。中斷的優先級說明的是當一箇中斷正在被處理的時候,處理器能接受的中斷的級別。中斷的優先級也代表了中斷須要被處理的緊急程度。每一箇中斷都有一個對應的優先級,當處理器在處理某一中斷的時候,只有比這個中斷優先級高的中斷能夠被處理器接受而且被處理。優先級比這個當前正在被處理的中斷優先級要低的中斷將會被忽略。

典型的中斷優先級以下所示:

  • 機器錯誤 > 時鐘 > 磁盤 > 網絡設備 > 終端 > 軟件中斷

 

在講系統調用以前,先說下進程的執行在系統上的兩個級別:用戶級和核心級,也稱爲用戶態和系統態(user mode and kernel mode)

           用戶空間就是用戶進程所在的內存區域,相對的,系統空間就是操做系統佔據的內存區域。用戶進程和系統進程的全部數據都在內存中。處於用戶態的程序只能訪問用戶空間,而處於內核態的程序能夠訪問用戶空間和內核空間。

用戶態切換到內核態的方式以下:

  • 系統調用:程序的執行通常是在用戶態下執行的,但當程序須要使用操做系統提供的服務時,好比說打開某一設備、建立文件、讀寫文件(這些均屬於系統調用)等,就須要向操做系統發出調用服務的請求,這就是系統調用。

  • 異常:當CPU在執行運行在用戶態下的程序時,發生了某些事先不可知的異常,這時會觸發由當前運行進程切換處處理此異常的內核相關程序中,也就轉到了內核態,好比缺頁異常。

  • 外圍設備的中斷:當外圍設備完成用戶請求的操做後,會向CPU發出相應的中斷信號,這時CPU會暫停執行下一條即將要執行的指令轉而去執行與中斷信號對應的處理程序,若是先前執行的指令是用戶態下的程序,那麼這個轉換的過程天然也就發生了由用戶態到內核態的切換。好比硬盤讀寫操做完成,系統會切換到硬盤讀寫的中斷處理程序中執行後續操做等。

用戶態和核心態(內核態)之間的區別是什麼呢?

       權限不同。

  • 用戶態的進程能存取它們本身的指令和數據,但不能存取內核指令和數據(或其餘進程的指令和數據)

  • 核心態下的進程可以存取內核和用戶地址某些機器指令是特權指令,在用戶態下執行特權指令會引發錯誤。在系統中內核並非做爲一個與用戶進程平行的估計的進程的集合。

15.C++多線程,互斥,同步

同步和互斥

當有多個線程的時候,常常須要去同步(注:同步不是同時刻)這些線程以訪問同一個數據或資源。例如,假設有一個程序,其中一個線程用於把文件讀到內存,而另外一個線程用於統計文件中的字符數。固然,在把整個文件調入內存以前,統計它的計數是沒有意義的。可是,因爲每一個操做都有本身的線程,操做系統會把兩個線程看成是互不相干的任務分別執行,這樣就可能在沒有把整個文件裝入內存時統計字數。爲解決此問題,你必須使兩個線程同步工做。

所謂同步,是指在不一樣進程之間的若干程序片段,它們的運行必須嚴格按照規定的某種前後次序來運行,這種前後次序依賴於要完成的特定的任務。若是用對資源的訪問來定義的話,同步是指在互斥的基礎上(大多數狀況),經過其它機制實現訪問者對資源的有序訪問。在大多數狀況下,同步已經實現了互斥,特別是全部寫入資源的狀況一定是互斥的。少數狀況是指能夠容許多個訪問者同時訪問資源。

所謂互斥,是指散佈在不一樣進程之間的若干程序片段,當某個進程運行其中一個程序片斷時,其它進程就不能運行它們之中的任一程序片斷,只能等到該進程運行完這個程序片斷後才能夠運行。若是用對資源的訪問來定義的話,互斥某一資源同時只容許一個訪問者對其進行訪問,具備惟一性和排它性。但互斥沒法限制訪問者對資源的訪問順序,即訪問是無序的。

多線程同步和互斥有幾種實現方法

線程間的同步方法大致可分爲兩類:用戶模式和內核模式。顧名思義,內核模式就是指利用系統內核對象的單一性來進行同步,使用時須要切換內核態與用戶態,而用戶模式就是不須要切換到內核態,只在用戶態完成操做。

用戶模式下的方法有:原子操做(例如一個單一的全局變量),臨界區。

內核模式下的方法有:事件,信號量,互斥量。

一、臨界區:經過對多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數據訪問。 
二、互斥量:爲協調共同對一個共享資源的單獨訪問而設計的。 
三、信號量:爲控制一個具備有限數量用戶資源而設計。 
四、事 件:用來通知線程有一些事件已發生,從而啓動後繼任務的開始。

16.邏輯地址 Vs 物理地址 Vs 虛擬內存

  • 所謂的邏輯地址,是指計算機用戶(例如程序開發者),看到的地址。例如,當建立一個長度爲100的整型數組時,操做系統返回一個邏輯上的連續空間:指針指向數組第一個元素的內存地址。因爲整型元素的大小爲4個字節,故第二個元素的地址時起始地址加4,以此類推。事實上,邏輯地址並不必定是元素存儲的真實地址,即數組元素的物理地址(在內存條中所處的位置),並不是是連續的,只是操做系統經過地址映射,將邏輯地址映射成連續的,這樣更符合人們的直觀思惟

  • 另外一個重要概念是虛擬內存。操做系統讀寫內存的速度能夠比讀寫磁盤的速度快幾個量級。可是,內存價格也相對較高,不能大規模擴展。因而,操做系統能夠經過將部分不太經常使用的數據移出內存,「存放到價格相對較低的磁盤緩存,以實現內存擴展。操做系統還能夠經過算法預測哪部分存儲到磁盤緩存的數據須要進行讀寫,提早把這部分數據讀回內存。虛擬內存空間相對磁盤而言要小不少,所以,即便搜索虛擬內存空間也比直接搜索磁盤要快。惟一慢於磁盤的多是,內存、虛擬內存中都沒有所須要的數據,最終還須要從硬盤中直接讀取。這就是爲何內存和虛擬內存中須要存儲會被重複讀寫的數據,不然就失去了緩存的意義。現代計算機中有一個專門的轉譯緩衝區(Translation Lookaside Buffer,TLB),用來實現虛擬地址到物理地址的快速轉換。

與內存/虛擬內存相關的還有以下兩個概念:
1) Resident Set

  • 當一個進程在運行的時候,操做系統不會一次性加載進程的全部數據到內存,只會加載一部分正在用,以及預期要用的數據。其餘數據可能存儲在虛擬內存,交換區和硬盤文件系統上。被加載到內存的部分就是resident set。

2) Thrashing

  • 因爲resident set包含預期要用的數據,理想狀況下,進程運行過程當中用到的數據都會逐步加載進resident set。但事實每每並不是如此:每當須要的內存頁面(page)不在resident set中時,操做系統必須從虛擬內存或硬盤中讀數據,這個過程被稱爲內存頁面錯誤(page faults)。當操做系統須要花費大量時間去處理頁面錯誤的狀況就是thrashing。

參考連接:https://blog.csdn.net/newcong0123/article/details/52792070

17.內部碎片與外部碎片

在內存管理中,內部碎片是已經被分配出去的的內存空間大於請求所需的內存空間。

外部碎片是指尚未分配出去,可是因爲大小過小而沒法分配給申請空間的新進程的內存空間空閒塊。

固定分區存在內部碎片,可變式分區分配會存在外部碎片;

頁式虛擬存儲系統存在內部碎片段式虛擬存儲系統,存在外部碎片

爲了有效的利用內存,使內存產生更少的碎片,要對內存分頁,內存以頁爲單位來使用,最後一頁每每裝不滿,因而造成了內部碎片。

爲了共享要分段,在段的換入換出時造成外部碎片,好比5K的段換出後,有一個4k的段進來放到原來5k的地方,因而造成1k的外部碎片。

18.同步和互斥的區別

        當有多個線程的時候,常常須要去同步這些線程以訪問同一個數據或資源。例如,假設有一個程序,其中一個線程用於把文件讀到內存,而另外一個線程用於統計文件中的字符數。固然,在把整個文件調入內存以前,統計它的計數是沒有意義的。可是,因爲每一個操做都有本身的線程,操做系統會把兩個線程看成是互不相干的任務分別執行,這樣就可能在沒有把整個文件裝入內存時統計字數。爲解決此問題,你必須使兩個線程同步工做。

      所謂同步,是指散步在不一樣進程之間的若干程序片段,它們的運行必須嚴格按照規定的某種前後次序來運行,這種前後次序依賴於要完成的特定的任務。若是用對資源的訪問來定義的話,同步是指在互斥的基礎上(大多數狀況),經過其它機制實現訪問者對資源的有序訪問。在大多數狀況下,同步已經實現了互斥,特別是全部寫入資源的狀況一定是互斥的。少數狀況是指能夠容許多個訪問者同時訪問資源。

      所謂互斥,是指散佈在不一樣進程之間的若干程序片段,當某個進程運行其中一個程序片斷時,其它進程就不能運行它們之中的任一程序片斷,只能等到該進程運行完這個程序片斷後才能夠運行。若是用對資源的訪問來定義的話,互斥某一資源同時只容許一個訪問者對其進行訪問,具備惟一性和排它性。但互斥沒法限制訪問者對資源的訪問順序,即訪問是無序的。

19.什麼是線程安全

若是多線程的程序運行結果是可預期的,並且與單線程的程序運行結果同樣,那麼說明是「線程安全」的。

20.同步與異步

同步:

  • 同步的定義:是指一個進程在執行某個請求的時候,若該請求須要一段時間才能返回信息,那麼,這個進程將會一直等待下去,直到收到返回信息才繼續執行下去。
  • 特色:
  1. 同步是阻塞模式;
  2. 同步是按順序執行,執行完一個再執行下一個,須要等待,協調運行;

異步:

  • 是指進程不須要一直等下去,而是繼續執行下面的操做,無論其餘進程的狀態。當有消息返回時系統會通知進程進行處理,這樣能夠提升執行的效率。
  • 特色:
  1. 異步是非阻塞模式,無需等待;
  2. 異步是彼此獨立,在等待某事件的過程當中,繼續作本身的事,不須要等待這一事件完成後再工做。線程是異步實現的一個方式。

同步與異步的優缺點:

  • 同步能夠避免出現死鎖,讀髒數據的發生。通常共享某一資源的時候,若是每一個人都有修改權限,同時修改一個文件,有可能使一個讀取另外一我的已經刪除了內容,就會出錯,同步就不會出錯。但,同步須要等待資源訪問結束,浪費時間,效率低。
  • 異步能夠提升效率,但,安全性較低。

21.系統調用與庫函數的區別

  • 系統調用(System call)是程序向系統內核請求服務的方式。能夠包括硬件相關的服務(例如,訪問硬盤等),或者建立新進程,調度其餘進程等。系統調用是程序和操做系統之間的重要接口。

  • 庫函數:把一些經常使用的函數編寫完放到一個文件裏,編寫應用程序時調用,這是由第三方提供的,發生在用戶地址空間

  • 移植性方面,不一樣操做系統的系統調用通常是不一樣的,移植性差;而在全部的ANSI C編譯器版本中,C庫函數是相同的。

  • 調用開銷方面,系統調用須要在用戶空間和內核環境間切換,開銷較大;而庫函數調用屬於「過程調用」,開銷較小。

22.守護、殭屍、孤兒進程的概念

  • 守護進程:運行在後臺的一種特殊進程,獨立於控制終端並週期性地執行某些任務

  • 殭屍進程:一個進程 fork 子進程,子進程退出,而父進程沒有wait/waitpid子進程,那麼子進程的進程描述符仍保存在系統中,這樣的進程稱爲殭屍進程。

  • 孤兒進程:一個父進程退出,而它的一個或多個子進程還在運行,這些子進程稱爲孤兒進程。(孤兒進程將由 init 進程收養並對它們完成狀態收集工做)

23.Semaphore(信號量) Vs Mutex(互斥鎖)

  • 當用戶創立多個線程/進程時,若是不一樣線程/進程同時讀寫相同的內容,則可能形成讀寫錯誤,或者數據不一致。此時,須要經過加鎖的方式,控制臨界區(critical section)的訪問權限。對於semaphore而言,在初始化變量的時候能夠控制容許多少個線程/進程同時訪問一個臨界區,其餘的線程/進程會被堵塞,直到有人解鎖。

  • Mutex至關於只容許一個線程/進程訪問的semaphore。此外,根據實際須要,人們還實現了一種讀寫鎖(read-write lock),它容許同時存在多個閱讀者(reader),但任什麼時候候至多隻有一個寫者(writer),且不能於讀者共存。

24.IO多路複用

IO多路複用是指內核一旦發現進程指定的一個或者多個IO條件準備讀取,它就通知該進程。IO多路複用適用以下場合:

  • 當客戶處理多個描述字時(通常是交互式輸入和網絡套接口),必須使用I/O複用。

  • 當一個客戶同時處理多個套接口時,而這種狀況是可能的,但不多出現。

  • 若是一個TCP服務器既要處理監聽套接口,又要處理已鏈接套接口,通常也要用到I/O複用。

  • 若是一個服務器即要處理TCP,又要處理UDP,通常要使用I/O複用。

  • 若是一個服務器要處理多個服務或多個協議,通常要使用I/O複用。

  • 與多進程和多線程技術相比,I/O多路複用技術的最大優點是系統開銷小,系統沒必要建立進程/線程,也沒必要維護這些進程/線程,從而大大減少了系統的開銷。

25.線程安全

若是你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。若是每次運行結果和單線程運行的結果是同樣的,並且其餘的變量的值也和預期的是同樣的,就是線程安全的。或者說:一個類或者程序所提供的接口對於線程來講是原子操做或者多個線程之間的切換不會致使該接口的執行結果存在二義性,也就是說咱們不用考慮同步的問題。

線程安全問題都是由 全局變量靜態變量引發的。
若每一個線程中對全局變量、靜態變量只有讀操做,而無寫操做,通常來講,這個全局變量是線程安全的;如有多個線程同時執行寫操做,通常都須要考慮 線程同步,不然的話就可能影響線程安全。
 

26.線程共享資源和獨佔資源問題

參考連接

一個進程中的全部線程共享該進程的地址空間,但它們有各自獨立的(/私有的)棧(stack),Windows線程的缺省堆棧大小爲1M。堆(heap)的分配與棧有所不一樣,通常是一個進程有一個C運行時堆,這個堆爲本進程中全部線程共享,windows進程還有所謂進程默認堆,用戶也能夠建立本身的堆。 
用操做系統術語,線程切換的時候實際上切換的是一個能夠稱之爲線程控制塊的結構(TCB),裏面保存全部未來用於恢復線程環境必須的信息,包括全部必須保存的寄存器集,線程的狀態等。

堆: 是你們共有的空間,分全局堆和局部堆。全局堆就是全部沒有分配的空間,局部堆就是用戶分配的空間。堆在操做系統對進程初始化的時候分配,運行過程當中也能夠向系統要額外的堆,可是記得用完了要還給操做系統,要否則就是內存泄漏。

棧:是個線程獨有的,保存其運行狀態和局部自動變量的。棧在線程開始的時候初始化,每一個線程的棧互相獨立,所以,棧是 thread safe的。操做系統在切換線程的時候會自動的切換棧,就是切換 SS/ESP寄存器。棧空間不須要在高級語言裏面顯式的分配和釋放。

相關文章
相關標籤/搜索