操作系统饥饿现象_操作系统常见面试题
1.進(jìn)程的常見狀態(tài)?以及各種狀態(tài)之間的轉(zhuǎn)換條件?
就緒:進(jìn)程已處于準(zhǔn)備好運(yùn)行的狀態(tài),即進(jìn)程已分配到除CPU外的所有必要資源后,只要再獲得CPU,便可立即執(zhí)行。
執(zhí)行:進(jìn)程已經(jīng)獲得CPU,程序正在執(zhí)行狀態(tài)。
阻塞:正在執(zhí)行的進(jìn)程由于發(fā)生某事件(如I/O請(qǐng)求、申請(qǐng)緩沖區(qū)失敗等)暫時(shí)無法繼續(xù)執(zhí)行的狀態(tài)。
2.進(jìn)程同步
進(jìn)程同步的主要任務(wù):是對(duì)多個(gè)相關(guān)進(jìn)程在執(zhí)行次序上進(jìn)行協(xié)調(diào),以使并發(fā)執(zhí)行的諸進(jìn)程之間能有效地共享資源和相互合作,從而使程序的執(zhí)行具有可再現(xiàn)性。
同步機(jī)制遵循的原則:
(1)空閑讓進(jìn);
(2)忙則等待(保證對(duì)臨界區(qū)的互斥訪問);
(3)有限等待(有限代表有限的時(shí)間,避免死等);
(4)讓權(quán)等待,(當(dāng)進(jìn)程不能進(jìn)入自己的臨界區(qū)時(shí),應(yīng)該釋放處理機(jī),以免陷入忙等狀態(tài))。
3.進(jìn)程的通信方式有哪些?
進(jìn)程通信,是指進(jìn)程之間的信息交換(信息量少則一個(gè)狀態(tài)或數(shù)值,多者則是成千上萬個(gè)字節(jié))。因此,對(duì)于用信號(hào)量進(jìn)行的進(jìn)程間的互斥和同步,由于其所交換的信息量少而被歸結(jié)為低級(jí)通信。
所謂高級(jí)進(jìn)程通信指:用戶可以利用操作系統(tǒng)所提供的一組通信命令傳送大量數(shù)據(jù)的一種通信方式。操作系統(tǒng)隱藏了進(jìn)程通信的實(shí)現(xiàn)細(xì)節(jié)。或者說,通信過程對(duì)用戶是透明的。
高級(jí)通信機(jī)制可歸結(jié)為三大類:
(1)共享存儲(chǔ)器系統(tǒng)(存儲(chǔ)器中劃分的共享存儲(chǔ)區(qū));實(shí)際操作中對(duì)應(yīng)的是“剪貼板”(剪貼板實(shí)際上是系統(tǒng)維護(hù)管理的一塊內(nèi)存區(qū)域)的通信方式,比如舉例如下:word進(jìn)程按下ctrl+c,在ppt進(jìn)程按下ctrl+v,即完成了word進(jìn)程和ppt進(jìn)程之間的通信,復(fù)制時(shí)將數(shù)據(jù)放入到剪貼板,粘貼時(shí)從剪貼板中取出數(shù)據(jù),然后顯示在ppt窗口上。
(2)消息傳遞系統(tǒng)(進(jìn)程間的數(shù)據(jù)交換以消息(message)為單位,當(dāng)今最流行的微內(nèi)核操作系統(tǒng)中,微內(nèi)核與服務(wù)器之間的通信,無一例外地都采用了消息傳遞機(jī)制。應(yīng)用舉例:郵槽(MailSlot)是基于廣播通信體系設(shè)計(jì)出來的,它采用無連接的不可靠的數(shù)據(jù)傳輸。郵槽是一種單向通信機(jī)制,創(chuàng)建郵槽的服務(wù)器進(jìn)程讀取數(shù)據(jù),打開郵槽的客戶機(jī)進(jìn)程寫入數(shù)據(jù)。
(3)管道通信系統(tǒng)(管道即:連接讀寫進(jìn)程以實(shí)現(xiàn)他們之間通信的共享文件(pipe文件,類似先進(jìn)先出的隊(duì)列,由一個(gè)進(jìn)程寫,另一進(jìn)程讀))。實(shí)際操作中,管道分為:匿名管道、命名管道。匿名管道是一個(gè)未命名的、單向管道,通過父進(jìn)程和一個(gè)子進(jìn)程之間傳輸數(shù)據(jù)。匿名管道只能實(shí)現(xiàn)本地機(jī)器上兩個(gè)進(jìn)程之間的通信,而不能實(shí)現(xiàn)跨網(wǎng)絡(luò)的通信。命名管道不僅可以在本機(jī)上實(shí)現(xiàn)兩個(gè)進(jìn)程間的通信,還可以跨網(wǎng)絡(luò)實(shí)現(xiàn)兩個(gè)進(jìn)程間的通信。
管道:管道是單向的、先進(jìn)先出的、無結(jié)構(gòu)的、固定大小的字節(jié)流,它把一個(gè)進(jìn)程的標(biāo)準(zhǔn)輸出和另一個(gè)進(jìn)程的標(biāo)準(zhǔn)輸入連接在一起。寫進(jìn)程在管道的尾端寫入數(shù)據(jù),讀進(jìn)程在管道的道端讀出數(shù)據(jù)。數(shù)據(jù)讀出后將從管道中移走,其它讀進(jìn)程都不能再讀到這些數(shù)據(jù)。管道提供了簡(jiǎn)單的流控制機(jī)制。進(jìn)程試圖讀空管道時(shí),在有數(shù)據(jù)寫入管道前,進(jìn)程將一直阻塞。同樣地,管道已經(jīng)滿時(shí),進(jìn)程再試圖寫管道,在其它進(jìn)程從管道中移走數(shù)據(jù)之前,寫進(jìn)程將一直阻塞。
注1:無名管道只能實(shí)現(xiàn)父子或者兄弟進(jìn)程之間的通信,有名管道(FIFO)可以實(shí)現(xiàn)互不相關(guān)的兩個(gè)進(jìn)程之間的通信。
注2:用FIFO讓一個(gè)服務(wù)器和多個(gè)客戶端進(jìn)行交流時(shí)候,每個(gè)客戶在向服務(wù)器發(fā)送信息前建立自己的讀管道,或者讓服務(wù)器在得到數(shù)據(jù)后再建立管道。使用客戶的進(jìn)程號(hào)(pid)作為管道名是一種常用的方法。客戶可以先把自己的進(jìn)程號(hào)告訴服務(wù)器,然后再到那個(gè)以自己進(jìn)程號(hào)命名的管道中讀取回復(fù)。
信號(hào)量:信號(hào)量是一個(gè)計(jì)數(shù)器,可以用來控制多個(gè)進(jìn)程對(duì)共享資源的訪問。它常作為一種鎖機(jī)制,防止某進(jìn)程正在訪問共享資源時(shí),其它進(jìn)程也訪問該資源。因此,主要作為進(jìn)程間以及同一進(jìn)程內(nèi)不同線程之間的同步手段。
消息隊(duì)列:是一個(gè)在系統(tǒng)內(nèi)核中用來保存消? 息的隊(duì)列,它在系統(tǒng)內(nèi)核中是以消息鏈表的形式出現(xiàn)的。消息隊(duì)列克服了信號(hào)傳遞信息少、管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等缺點(diǎn)。
共享內(nèi)存:共享內(nèi)存允許兩個(gè)或多個(gè)進(jìn)程訪問同一個(gè)邏輯內(nèi)存。這一段內(nèi)存可以被兩個(gè)或兩個(gè)以上的進(jìn)程映射至自身的地址空間中,一個(gè)進(jìn)程寫入共享內(nèi)存的信息,可以被其他使用這個(gè)共享內(nèi)存的進(jìn)程,通過一個(gè)簡(jiǎn)單的內(nèi)存讀取讀出,從而實(shí)現(xiàn)了進(jìn)程間的通信。如果某個(gè)進(jìn)程向共享內(nèi)存寫入數(shù)據(jù),所做的改動(dòng)將立即影響到可以訪問同一段共享內(nèi)存的任何其他進(jìn)程。共享內(nèi)存是最快的IPC方式,它是針對(duì)其它進(jìn)程間通信方式運(yùn)行效率低而專門設(shè)計(jì)的。它往往與其它通信機(jī)制(如信號(hào)量)配合使用,來實(shí)現(xiàn)進(jìn)程間的同步和通信。
套接字:套接字也是一種進(jìn)程間通信機(jī)制,與其它通信機(jī)制不同的是,它可用于不同機(jī)器間的進(jìn)程通信。
4.上下文切換
對(duì)于單核單線程CPU而言,在某一時(shí)刻只能執(zhí)行一條CPU指令。上下文切換(Context Switch)是一種將CPU資源從一個(gè)進(jìn)程分配給另一個(gè)進(jìn)程的機(jī)制。從用戶角度看,計(jì)算機(jī)能夠并行運(yùn)行多個(gè)進(jìn)程,這恰恰是操作系統(tǒng)通過快速上下文切換造成的結(jié)果。在切換的過程中,操作系統(tǒng)需要先存儲(chǔ)當(dāng)前進(jìn)程的狀態(tài)(包括內(nèi)存空間的指針,當(dāng)前執(zhí)行完的指令等等),再讀入下一個(gè)進(jìn)程的狀態(tài),然后執(zhí)行此進(jìn)程。
5.進(jìn)程與線程的區(qū)別和聯(lián)系?
進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。
線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位。
進(jìn)程和線程的關(guān)系
(1)一個(gè)線程只能屬于一個(gè)進(jìn)程,而一個(gè)進(jìn)程可以有多個(gè)線程,但至少有一個(gè)線程。線程是操作系統(tǒng)可識(shí)別的最小執(zhí)行和調(diào)度單位。
(2)資源分配給進(jìn)程,同一進(jìn)程的所有線程共享該進(jìn)程的所有資源。 同一進(jìn)程中的多個(gè)線程共享代碼段(代碼和常量),數(shù)據(jù)段(全局變量和靜態(tài)變量),擴(kuò)展段(堆存儲(chǔ))。但是每個(gè)線程擁有自己的棧段,棧段又叫運(yùn)行時(shí)段,用來存放所有局部變量和臨時(shí)變量。
(3)處理機(jī)分給線程,即真正在處理機(jī)上運(yùn)行的是線程。
(4)線程在執(zhí)行過程中,需要協(xié)作同步。不同進(jìn)程的線程間要利用消息通信的辦法實(shí)現(xiàn)同步。
進(jìn)程與線程的區(qū)別?
(1)進(jìn)程有自己的獨(dú)立地址空間,線程沒有
(2)進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位
(3)進(jìn)程和線程通信方式不同(線程之間的通信比較方便。同一進(jìn)程下的線程共享數(shù)據(jù)(比如全局變量,靜態(tài)變量),通過這些數(shù)據(jù)來通信不僅快捷而且方便,當(dāng)然如何處理好這些訪問的同步與互斥正是編寫多線程程序的難點(diǎn)。而進(jìn)程之間的通信只能通過進(jìn)程通信的方式進(jìn)行。)
(4)進(jìn)程上下文切換開銷大,線程開銷小
(5)一個(gè)進(jìn)程掛掉了不會(huì)影響其他進(jìn)程,而線程掛掉了會(huì)影響其他線程
(6)對(duì)進(jìn)程進(jìn)程操作一般開銷都比較大,對(duì)線程開銷就小了
為什么進(jìn)程上下文切換比線程上下文切換代價(jià)高?
進(jìn)程切換分兩步:
1.切換頁目錄以使用新的地址空間
2.切換內(nèi)核棧和硬件上下文
對(duì)于linux來說,線程和進(jìn)程的最大區(qū)別就在于地址空間,對(duì)于線程切換,第1步是不需要做的,第2是進(jìn)程和線程切換都要做的。
切換的性能消耗:
1、線程上下文切換和進(jìn)程上下問切換一個(gè)最主要的區(qū)別是線程的切換虛擬內(nèi)存空間依然是相同的,但是進(jìn)程切換是不同的。這兩種上下文切換的處理都是通過操作系統(tǒng)內(nèi)核來完成的。內(nèi)核的這種切換過程伴隨的最顯著的性能損耗是將寄存器中的內(nèi)容切換出。
2、另外一個(gè)隱藏的損耗是上下文的切換會(huì)擾亂處理器的緩存機(jī)制。簡(jiǎn)單的說,一旦去切換上下文,處理器中所有已經(jīng)緩存的內(nèi)存地址一瞬間都作廢了。還有一個(gè)顯著的區(qū)別是當(dāng)你改變虛擬內(nèi)存空間的時(shí)候,處理的頁表緩沖(processor's Translation Lookaside Buffer (TLB))或者相當(dāng)?shù)纳耨R東西會(huì)被全部刷新,這將導(dǎo)致內(nèi)存的訪問在一段時(shí)間內(nèi)相當(dāng)?shù)牡托А5窃诰€程的切換中,不會(huì)出現(xiàn)這個(gè)問題。
轉(zhuǎn)自知乎:進(jìn)程和線程的區(qū)別
鏈接:https://www.zhihu.com/question/25532384/answer/81152571
首先來一句概括的總論:進(jìn)程和線程都是一個(gè)時(shí)間段的描述,是CPU工作時(shí)間段的描述。
下面細(xì)說背景:
CPU+RAM+各種資源(比如顯卡,光驅(qū),鍵盤,GPS, 等等外設(shè))構(gòu)成我們的電腦,但是電腦的運(yùn)行,實(shí)際就是CPU和相關(guān)寄存器以及RAM之間的事情。
一個(gè)最最基礎(chǔ)的事實(shí):CPU太快,太快,太快了,寄存器僅僅能夠追的上他的腳步,RAM和別的掛在各總線上的設(shè)備完全是望其項(xiàng)背。那當(dāng)多個(gè)任務(wù)要執(zhí)行的時(shí)候怎么辦呢?輪流著來?或者誰優(yōu)先級(jí)高誰來?不管怎么樣的策略,一句話就是在CPU看來就是輪流著來。
一個(gè)必須知道的事實(shí):執(zhí)行一段程序代碼,實(shí)現(xiàn)一個(gè)功能的過程介紹 ,當(dāng)?shù)玫紺PU的時(shí)候,相關(guān)的資源必須也已經(jīng)就位,就是顯卡啊,GPS啊什么的必須就位,然后CPU開始執(zhí)行。這里除了CPU以外所有的就構(gòu)成了這個(gè)程序的執(zhí)行環(huán)境,也就是我們所定義的程序上下文。當(dāng)這個(gè)程序執(zhí)行完了,或者分配給他的CPU執(zhí)行時(shí)間用完了,那它就要被切換出去,等待下一次CPU的臨幸。在被切換出去的最后一步工作就是保存程序上下文,因?yàn)檫@個(gè)是下次他被CPU臨幸的運(yùn)行環(huán)境,必須保存。
串聯(lián)起來的事實(shí):前面講過在CPU看來所有的任務(wù)都是一個(gè)一個(gè)的輪流執(zhí)行的,具體的輪流方法就是:先加載程序A的上下文,然后開始執(zhí)行A,保存程序A的上下文,調(diào)入下一個(gè)要執(zhí)行的程序B的程序上下文,然后開始執(zhí)行B,保存程序B的上下文。。。。========= 重要的東西出現(xiàn)了========進(jìn)程和線程就是這樣的背景出來的,兩個(gè)名詞不過是對(duì)應(yīng)的CPU時(shí)間段的描述,名詞就是這樣的功能。
進(jìn)程就是包換上下文切換的程序執(zhí)行時(shí)間總和 = CPU加載上下文+CPU執(zhí)行+CPU保存上下文
線程是什么呢?進(jìn)程的顆粒度太大,每次都要有上下的調(diào)入,保存,調(diào)出。如果我們把進(jìn)程比喻為一個(gè)運(yùn)行在電腦上的軟件,那么一個(gè)軟件的執(zhí)行不可能是一條邏輯執(zhí)行的,必定有多個(gè)分支和多個(gè)程序段,就好比要實(shí)現(xiàn)程序A,實(shí)際分成 a,b,c等多個(gè)塊組合而成。那么這里具體的執(zhí)行就可能變成:
程序A得到CPU =》CPU加載上下文,開始執(zhí)行程序A的a小段,然后執(zhí)行A的b小段,然后再執(zhí)行A的c小段,最后CPU保存A的上下文。
這里a,b,c的執(zhí)行是共享了A的上下文,CPU在執(zhí)行的時(shí)候沒有進(jìn)行上下文切換的。這里的a,b,c就是線程,也就是說線程是共享了進(jìn)程的上下文環(huán)境,的更為細(xì)小的CPU時(shí)間段。
到此全文結(jié)束,再一個(gè)總結(jié):
進(jìn)程和線程都是一個(gè)時(shí)間段的描述,是CPU工作時(shí)間段的描述,不過是顆粒大小不同。
進(jìn)程(process)與線程(thread)最大的區(qū)別是進(jìn)程擁有自己的地址空間,某進(jìn)程內(nèi)的線程對(duì)于其他進(jìn)程不可見,即進(jìn)程A不能通過傳地址的方式直接讀寫進(jìn)程B的存儲(chǔ)區(qū)域。進(jìn)程之間的通信需要通過進(jìn)程間通信(Inter-process communication,IPC)。與之相對(duì)的,同一進(jìn)程的各線程間之間可以直接通過傳遞地址或全局變量的方式傳遞信息。
進(jìn)程作為操作系統(tǒng)中擁有資源和獨(dú)立調(diào)度的基本單位,可以擁有多個(gè)線程。通常操作系統(tǒng)中運(yùn)行的一個(gè)程序就對(duì)應(yīng)一個(gè)進(jìn)程。在同一進(jìn)程中,線程的切換不會(huì)引起進(jìn)程切換。在不同進(jìn)程中進(jìn)行線程切換,如從一個(gè)進(jìn)程內(nèi)的線程切換到另一個(gè)進(jìn)程中的線程時(shí),會(huì)引起進(jìn)程切換。相比進(jìn)程切換,線程切換的開銷要小很多。線程于進(jìn)程相互結(jié)合能夠提高系統(tǒng)的運(yùn)行效率。
線程可以分為兩類:
用戶級(jí)線程(user level thread):對(duì)于這類線程,有關(guān)線程管理的所有工作都由應(yīng)用程序完成,內(nèi)核意識(shí)不到線程的存在。在應(yīng)用程序啟動(dòng)后,操作系統(tǒng)分配給該程序一個(gè)進(jìn)程號(hào),以及其對(duì)應(yīng)的內(nèi)存空間等資源。應(yīng)用程序通常先在一個(gè)線程中運(yùn)行,該線程被成為主線程。在其運(yùn)行的某個(gè)時(shí)刻,可以通過調(diào)用線程庫中的函數(shù)創(chuàng)建一個(gè)在相同進(jìn)程中運(yùn)行的新線程。用戶級(jí)線程的好處是非常高效,不需要進(jìn)入內(nèi)核空間,但并發(fā)效率不高。
內(nèi)核級(jí)線程(kernel level thread):對(duì)于這類線程,有關(guān)線程管理的所有工作由內(nèi)核完成,應(yīng)用程序沒有進(jìn)行線程管理的代碼,只能調(diào)用內(nèi)核線程的接口。內(nèi)核維護(hù)進(jìn)程及其內(nèi)部的每個(gè)線程,調(diào)度也由內(nèi)核基于線程架構(gòu)完成。內(nèi)核級(jí)線程的好處是,內(nèi)核可以將不同線程更好地分配到不同的CPU,以實(shí)現(xiàn)真正的并行計(jì)算。
事實(shí)上,在現(xiàn)代操作系統(tǒng)中,往往使用組合方式實(shí)現(xiàn)多線程,即線程創(chuàng)建完全在用戶空間中完成,并且一個(gè)應(yīng)用程序中的多個(gè)用戶級(jí)線程被映射到一些內(nèi)核級(jí)線程上,相當(dāng)于是一種折中方案。
6.進(jìn)程調(diào)度
調(diào)度種類
高級(jí)調(diào)度:(High-Level Scheduling)又稱為作業(yè)調(diào)度,它決定把后備作業(yè)調(diào)入內(nèi)存運(yùn)行;
低級(jí)調(diào)度:(Low-Level Scheduling)又稱為進(jìn)程調(diào)度,它決定把就緒隊(duì)列的某進(jìn)程獲得CPU;
中級(jí)調(diào)度:(Intermediate-Level Scheduling)又稱為在虛擬存儲(chǔ)器中引入,在內(nèi)、外存對(duì)換區(qū)進(jìn)行進(jìn)程對(duì)換。
非搶占式調(diào)度與搶占式調(diào)度
非搶占式:分派程序一旦把處理機(jī)分配給某進(jìn)程后便讓它一直運(yùn)行下去,直到進(jìn)程完成或發(fā)生進(jìn)程調(diào)度進(jìn)程調(diào)度某事件而阻塞時(shí),才把處理機(jī)分配給另一個(gè)進(jìn)程。
搶占式:操作系統(tǒng)將正在運(yùn)行的進(jìn)程強(qiáng)行暫停,由調(diào)度程序?qū)PU分配給其他就緒進(jìn)程的調(diào)度方式。
調(diào)度策略的設(shè)計(jì)
響應(yīng)時(shí)間: 從用戶輸入到產(chǎn)生反應(yīng)的時(shí)間
周轉(zhuǎn)時(shí)間: 從任務(wù)開始到任務(wù)結(jié)束的時(shí)間
CPU任務(wù)可以分為交互式任務(wù)和批處理任務(wù),調(diào)度最終的目標(biāo)是合理的使用CPU,使得交互式任務(wù)的響應(yīng)時(shí)間盡可能短,用戶不至于感到延遲,同時(shí)使得批處理任務(wù)的周轉(zhuǎn)時(shí)間盡可能短,減少用戶等待的時(shí)間。
調(diào)度算法:
FIFO或First Come, First Served (FCFS)先來先服務(wù)
調(diào)度的順序就是任務(wù)到達(dá)就緒隊(duì)列的順序。
公平、簡(jiǎn)單(FIFO隊(duì)列)、非搶占、不適合交互式。
未考慮任務(wù)特性,平均等待時(shí)間可以縮短。
Shortest Job First (SJF)
最短的作業(yè)(CPU區(qū)間長(zhǎng)度最小)最先調(diào)度。
SJF可以保證最小的平均等待時(shí)間。
Shortest Remaining Job First (SRJF)
SJF的可搶占版本,比SJF更有優(yōu)勢(shì)。
SJF(SRJF): 如何知道下一CPU區(qū)間大小?根據(jù)歷史進(jìn)行預(yù)測(cè): 指數(shù)平均法。
優(yōu)先權(quán)調(diào)度
每個(gè)任務(wù)關(guān)聯(lián)一個(gè)優(yōu)先權(quán),調(diào)度優(yōu)先權(quán)最高的任務(wù)。
注意:優(yōu)先權(quán)太低的任務(wù)一直就緒,得不到運(yùn)行,出現(xiàn)“饑餓”現(xiàn)象。
Round-Robin(RR)輪轉(zhuǎn)調(diào)度算法
設(shè)置一個(gè)時(shí)間片,按時(shí)間片來輪轉(zhuǎn)調(diào)度(“輪叫”算法)
優(yōu)點(diǎn): 定時(shí)有響應(yīng),等待時(shí)間較短;缺點(diǎn): 上下文切換次數(shù)較多;
時(shí)間片太大,響應(yīng)時(shí)間太長(zhǎng);吞吐量變小,周轉(zhuǎn)時(shí)間變長(zhǎng);當(dāng)時(shí)間片過長(zhǎng)時(shí),退化為FCFS。
多級(jí)隊(duì)列調(diào)度
按照一定的規(guī)則建立多個(gè)進(jìn)程隊(duì)列
不同的隊(duì)列有固定的優(yōu)先級(jí)(高優(yōu)先級(jí)有搶占權(quán))
不同的隊(duì)列可以給不同的時(shí)間片和采用不同的調(diào)度方法
存在問題1:沒法區(qū)分I/O bound和CPU bound;
存在問題2:也存在一定程度的“饑餓”現(xiàn)象;
多級(jí)反饋隊(duì)列
在多級(jí)隊(duì)列的基礎(chǔ)上,任務(wù)可以在隊(duì)列之間移動(dòng),更細(xì)致的區(qū)分任務(wù)。
可以根據(jù)“享用”CPU時(shí)間多少來移動(dòng)隊(duì)列,阻止“饑餓”。
最通用的調(diào)度算法,多數(shù)OS都使用該方法或其變形,如UNIX、Windows等。
多級(jí)反饋隊(duì)列調(diào)度算法描述:
進(jìn)程在進(jìn)入待調(diào)度的隊(duì)列等待時(shí),首先進(jìn)入優(yōu)先級(jí)最高的Q1等待。
首先調(diào)度優(yōu)先級(jí)高的隊(duì)列中的進(jìn)程。若高優(yōu)先級(jí)中隊(duì)列中已沒有調(diào)度的進(jìn)程,則調(diào)度次優(yōu)先級(jí)隊(duì)列中的進(jìn)程。例如:Q1,Q2,Q3三個(gè)隊(duì)列,只有在Q1中沒有進(jìn)程等待時(shí)才去調(diào)度Q2,同理,只有Q1,Q2都為空時(shí)才會(huì)去調(diào)度Q3。
對(duì)于同一個(gè)隊(duì)列中的各個(gè)進(jìn)程,按照時(shí)間片輪轉(zhuǎn)法調(diào)度。比如Q1隊(duì)列的時(shí)間片為N,那么Q1中的作業(yè)在經(jīng)歷了N個(gè)時(shí)間片后若還沒有完成,則進(jìn)入Q2隊(duì)列等待,若Q2的時(shí)間片用完后作業(yè)還不能完成,一直進(jìn)入下一級(jí)隊(duì)列,直至完成。
在低優(yōu)先級(jí)的隊(duì)列中的進(jìn)程在運(yùn)行時(shí),又有新到達(dá)的作業(yè),那么在運(yùn)行完這個(gè)時(shí)間片后,CPU馬上分配給新到達(dá)的作業(yè)(搶占式)。
一個(gè)簡(jiǎn)單的例子
假設(shè)系統(tǒng)中有3個(gè)反饋隊(duì)列Q1,Q2,Q3,時(shí)間片分別為2,4,8。現(xiàn)在有3個(gè)作業(yè)J1,J2,J3分別在時(shí)間 0 ,1,3時(shí)刻到達(dá)。而它們所需要的CPU時(shí)間分別是3,2,1個(gè)時(shí)間片。
時(shí)刻0?J1到達(dá)。 于是進(jìn)入到隊(duì)列1 ,運(yùn)行1個(gè)時(shí)間片 ,時(shí)間片還未到,此時(shí)J2到達(dá)。
時(shí)刻1?J2到達(dá)。 由于時(shí)間片仍然由J1掌控,于是等待。J1在運(yùn)行了1個(gè)時(shí)間片后,已經(jīng)完成了在Q1中的2個(gè)時(shí)間片的限制,于是J1置于Q2等待被調(diào)度。現(xiàn)在處理機(jī)分配給J2。
時(shí)刻2?J1進(jìn)入Q2等待調(diào)度,J2獲得CPU開始運(yùn)行。
時(shí)刻3?J3到達(dá),由于J2的時(shí)間片未到,故J3在Q1等待調(diào)度,J1也在Q2等待調(diào)度。
時(shí)刻4?J2處理完成,由于J3,J1都在等待調(diào)度,但是J3所在的隊(duì)列比J1所在的隊(duì)列的優(yōu)先級(jí)要高,于是J3被調(diào)度,J1繼續(xù)在Q2等待。
時(shí)刻5?J3經(jīng)過1個(gè)時(shí)間片,完成。
時(shí)刻6?由于Q1已經(jīng)空閑,于是開始調(diào)度Q2中的作業(yè),則J1得到處理器開始運(yùn)行。 J1再經(jīng)過一個(gè)時(shí)間片,完成了任務(wù)。于是整個(gè)調(diào)度過程結(jié)束。
7.死鎖的條件?以及如何處理死鎖問題?
定義:如果一組進(jìn)程中的每一個(gè)進(jìn)程都在等待僅由該組進(jìn)程中的其他進(jìn)程才能引發(fā)的事件,那么該組進(jìn)程就是死鎖的。或者在兩個(gè)或多個(gè)并發(fā)進(jìn)程中,如果每個(gè)進(jìn)程持有某種資源而又都等待別的進(jìn)程釋放它或它們現(xiàn)在保持著的資源,在未改變這種狀態(tài)之前都不能向前推進(jìn),稱這一組進(jìn)程產(chǎn)生了死鎖。通俗地講,就是兩個(gè)或多個(gè)進(jìn)程被無限期地阻塞、相互等待的一種狀態(tài)。
產(chǎn)生死鎖的必要條件:
互斥條件(Mutual exclusion):資源不能被共享,只能由一個(gè)進(jìn)程使用。
請(qǐng)求與保持條件(Hold and wait):已經(jīng)得到資源的進(jìn)程可以再次申請(qǐng)新的資源。
非搶占條件(No pre-emption):已經(jīng)分配的資源不能從相應(yīng)的進(jìn)程中被強(qiáng)制地剝奪。
循環(huán)等待條件(Circular wait):系統(tǒng)中若干進(jìn)程組成環(huán)路,該環(huán)路中每個(gè)進(jìn)程都在等待相鄰進(jìn)程正占用的資源。
如何處理死鎖問題:
忽略該問題。例如鴕鳥算法,該算法可以應(yīng)用在極少發(fā)生死鎖的的情況下。為什么叫鴕鳥算法呢,因?yàn)閭髡f中鴕鳥看到危險(xiǎn)就把頭埋在地底下,可能鴕鳥覺得看不到危險(xiǎn)也就沒危險(xiǎn)了吧。跟掩耳盜鈴有點(diǎn)像。
檢測(cè)死鎖并且恢復(fù)。
仔細(xì)地對(duì)資源進(jìn)行動(dòng)態(tài)分配,使系統(tǒng)始終處于安全狀態(tài)以避免死鎖。
通過破除死鎖四個(gè)必要條件之一,來防止死鎖產(chǎn)生。
8.臨界資源
在操作系統(tǒng)中,進(jìn)程是占有資源的最小單位(線程可以訪問其所在進(jìn)程內(nèi)的所有資源,但線程本身并不占有資源或僅僅占有一點(diǎn)必須資源)。但對(duì)于某些資源來說,其在同一時(shí)間只能被一個(gè)進(jìn)程所占用。這些一次只能被一個(gè)進(jìn)程所占用的資源就是所謂的臨界資源。典型的臨界資源比如物理上的打印機(jī),或是存在硬盤或內(nèi)存中被多個(gè)進(jìn)程所共享的一些變量和數(shù)據(jù)等(如果這類資源不被看成臨界資源加以保護(hù),那么很有可能造成丟數(shù)據(jù)的問題)。
對(duì)于臨界資源的訪問,必須是互斥進(jìn)行。也就是當(dāng)臨界資源被占用時(shí),另一個(gè)申請(qǐng)臨界資源的進(jìn)程會(huì)被阻塞,直到其所申請(qǐng)的臨界資源被釋放。而進(jìn)程內(nèi)訪問臨界資源的代碼被成為臨界區(qū)。
9.一個(gè)程序從開始運(yùn)行到結(jié)束的完整過程(四個(gè)過程)
1、預(yù)處理:條件編譯,頭文件包含,宏替換的處理,生成.i文件。
2、編譯:將預(yù)處理后的文件轉(zhuǎn)換成匯編語言,生成.s文件
3、匯編:匯編變?yōu)槟繕?biāo)代碼(機(jī)器代碼)生成.o的文件
4、鏈接:連接目標(biāo)代碼,生成可執(zhí)行程序
10.內(nèi)存池、進(jìn)程池、線程池。(c++程序員必須掌握)
首先介紹一個(gè)概念“池化技術(shù) ”。池化技術(shù)就是:提前保存大量的資源,以備不時(shí)之需以及重復(fù)使用。池化技術(shù)應(yīng)用廣泛,如內(nèi)存池,線程池,連接池等等。內(nèi)存池相關(guān)的內(nèi)容,建議看看Apache、Nginx等開源web服務(wù)器的內(nèi)存池實(shí)現(xiàn)。
由于在實(shí)際應(yīng)用當(dāng)做,分配內(nèi)存、創(chuàng)建進(jìn)程、線程都會(huì)設(shè)計(jì)到一些系統(tǒng)調(diào)用,系統(tǒng)調(diào)用需要導(dǎo)致程序從用戶態(tài)切換到內(nèi)核態(tài),是非常耗時(shí)的操作。因此,當(dāng)程序中需要頻繁的進(jìn)行內(nèi)存申請(qǐng)釋放,進(jìn)程、線程創(chuàng)建銷毀等操作時(shí),通常會(huì)使用內(nèi)存池、進(jìn)程池、線程池技術(shù)來提升程序的性能。
線程池:線程池的原理很簡(jiǎn)單,類似于操作系統(tǒng)中的緩沖區(qū)的概念,它的流程如下:先啟動(dòng)若干數(shù)量的線程,并讓這些線程都處于睡眠狀態(tài),當(dāng)需要一個(gè)開辟一個(gè)線程去做具體的工作時(shí),就會(huì)喚醒線程池中的某一個(gè)睡眠線程,讓它去做具體工作,當(dāng)工作完成后,線程又處于睡眠狀態(tài),而不是將線程銷毀。
進(jìn)程池與線程池同理。
內(nèi)存池:內(nèi)存池是指程序預(yù)先從操作系統(tǒng)申請(qǐng)一塊足夠大內(nèi)存,此后,當(dāng)程序中需要申請(qǐng)內(nèi)存的時(shí)候,不是直接向操作系統(tǒng)申請(qǐng),而是直接從內(nèi)存池中獲取;同理,當(dāng)程序釋放內(nèi)存的時(shí)候,并不真正將內(nèi)存返回給操作系統(tǒng),而是返回內(nèi)存池。當(dāng)程序退出(或者特定時(shí)間)時(shí),內(nèi)存池才將之前申請(qǐng)的內(nèi)存真正釋放。
11.動(dòng)態(tài)鏈接庫與靜態(tài)鏈接庫的區(qū)別
靜態(tài)庫
靜態(tài)庫是一個(gè)外部函數(shù)與變量的集合體。靜態(tài)庫的文件內(nèi)容,通常包含一堆程序員自定的變量與函數(shù),其內(nèi)容不像動(dòng)態(tài)鏈接庫那么復(fù)雜,在編譯期間由編譯器與鏈接器將它集成至應(yīng)用程序內(nèi),并制作成目標(biāo)文件以及可以獨(dú)立運(yùn)作的可執(zhí)行文件。而這個(gè)可執(zhí)行文件與編譯可執(zhí)行文件的程序,都是一種程序的靜態(tài)創(chuàng)建(static build)。
動(dòng)態(tài)庫
靜態(tài)庫很方便,但是如果我們只是想用庫中的某一個(gè)函數(shù),卻仍然得把所有的內(nèi)容都鏈接進(jìn)去。一個(gè)更現(xiàn)代的方法則是使用共享庫,避免了在文件中靜態(tài)庫的大量重復(fù)。
動(dòng)態(tài)鏈接可以在首次載入的時(shí)候執(zhí)行(load-time linking),這是 Linux 的標(biāo)準(zhǔn)做法,會(huì)由動(dòng)態(tài)鏈接器ld-linux.so 完成,比方標(biāo)準(zhǔn) C 庫(libc.so) 通常就是動(dòng)態(tài)鏈接的,這樣所有的程序可以共享同一個(gè)庫,而不用分別進(jìn)行封裝。
動(dòng)態(tài)鏈接也可以在程序開始執(zhí)行的時(shí)候完成(run-time linking),在 Linux 中使用 dlopen()接口來完成(會(huì)使用函數(shù)指針),通常用于分布式軟件,高性能服務(wù)器上。而且共享庫也可以在多個(gè)進(jìn)程間共享。
鏈接使得我們可以用多個(gè)對(duì)象文件構(gòu)造我們的程序。可以在程序的不同階段進(jìn)行(編譯、載入、運(yùn)行期間均可),理解鏈接可以幫助我們避免遇到奇怪的錯(cuò)誤。
區(qū)別:
使用靜態(tài)庫的時(shí)候,靜態(tài)鏈接庫要參與編譯,在生成執(zhí)行文件之前的鏈接過程中,要將靜態(tài)鏈接庫的全部指令直接鏈接入可執(zhí)行文件中。而動(dòng)態(tài)庫提供了一種方法,使進(jìn)程可以調(diào)用不屬于其可執(zhí)行代碼的函數(shù)。函數(shù)的可執(zhí)行代碼位于一個(gè).dll文件中,該dll包含一個(gè)或多個(gè)已被編譯,鏈接并與使用它們的進(jìn)程分開儲(chǔ)存的函數(shù)。
靜態(tài)庫中不能再包含其他動(dòng)態(tài)庫或靜態(tài)庫,而在動(dòng)態(tài)庫中還可以再包含其他動(dòng)態(tài)或者靜態(tài)庫。
靜態(tài)庫在編譯的時(shí)候,就將庫函數(shù)裝在到程序中去了,而動(dòng)態(tài)庫函數(shù)必須在運(yùn)行的時(shí)候才被裝載,所以使用靜態(tài)庫速度快一些。
12.虛擬內(nèi)存?優(yōu)缺點(diǎn)?
定義:具有請(qǐng)求調(diào)入功能和置換功能,能從邏輯上對(duì)內(nèi)存容量加以擴(kuò)充得一種存儲(chǔ)器系統(tǒng)。其邏輯容量由內(nèi)存之和和外存之和決定。
與傳統(tǒng)存儲(chǔ)器比較虛擬存儲(chǔ)器有以下三個(gè)主要特征:
多次性,是指無需在作業(yè)運(yùn)行時(shí)一次性地全部裝入內(nèi)存,而是允許被分成多次調(diào)入內(nèi)存運(yùn)行。
對(duì)換性,是指無需在作業(yè)運(yùn)行時(shí)一直常駐內(nèi)存,而是允許在作業(yè)的運(yùn)行過程中,進(jìn)行換進(jìn)和換出。
虛擬性,是指從邏輯上擴(kuò)充內(nèi)存的容量,使用戶所看到的內(nèi)存容量,遠(yuǎn)大于實(shí)際的內(nèi)存容量。
虛擬內(nèi)存的實(shí)現(xiàn)有以下兩種方式:
請(qǐng)求分頁存儲(chǔ)管理。
請(qǐng)求分段存儲(chǔ)管理。
13.頁面置換算法
操作系統(tǒng)將內(nèi)存按照頁面進(jìn)行管理,在需要的時(shí)候才把進(jìn)程相應(yīng)的部分調(diào)入內(nèi)存。當(dāng)產(chǎn)生缺頁中斷時(shí),需要選擇一個(gè)頁面寫入。如果要換出的頁面在內(nèi)存中被修改過,變成了“臟”頁面,那就需要先寫會(huì)到磁盤。頁面置換算法,就是要選出最合適的一個(gè)頁面,使得置換的效率最高。頁面置換算法有很多,簡(jiǎn)單介紹幾個(gè),重點(diǎn)介紹比較重要的LRU及其實(shí)現(xiàn)算法。
一、最優(yōu)頁面置換算法
最理想的狀態(tài)下,我們給頁面做個(gè)標(biāo)記,挑選一個(gè)最遠(yuǎn)才會(huì)被再次用到的頁面調(diào)出。當(dāng)然,這樣的算法不可能實(shí)現(xiàn),因?yàn)椴淮_定一個(gè)頁面在何時(shí)會(huì)被用到。
二、先進(jìn)先出頁面置換算法(FIFO)及其改進(jìn)
這種算法的思想和隊(duì)列是一樣的,該算法總是淘汰最先進(jìn)入內(nèi)存的頁面,即選擇在內(nèi)存中駐留時(shí)間最久的頁面予淘汰。實(shí)現(xiàn):把一個(gè)進(jìn)程已調(diào)入內(nèi)存的頁面按先后次序鏈接成一個(gè)隊(duì)列,并且設(shè)置一個(gè)指針總是指向最老的頁面。缺點(diǎn):對(duì)于有些經(jīng)常被訪問的頁面如含有全局變量、常用函數(shù)、例程等的頁面,不能保證這些不被淘汰。
三、最近最少使用頁面置換算法LRU(Least Recently Used)
根據(jù)頁面調(diào)入內(nèi)存后的使用情況做出決策。LRU置換算法是選擇最近最久未使用的頁面進(jìn)行淘汰。
1.為每個(gè)在內(nèi)存中的頁面配置一個(gè)移位寄存器。(P165)定時(shí)信號(hào)將每隔一段時(shí)間將寄存器右移一位。最小數(shù)值的寄存器對(duì)應(yīng)頁面就是最久未使用頁面。
2.利用一個(gè)特殊的棧保存當(dāng)前使用的各個(gè)頁面的頁面號(hào)。每當(dāng)進(jìn)程訪問某頁面時(shí),便將該頁面的頁面號(hào)從棧中移出,將它壓入棧頂。因此,棧頂永遠(yuǎn)是最新被訪問的頁面號(hào),棧底是最近最久未被訪問的頁面號(hào)。
14.中斷與系統(tǒng)調(diào)用
所謂的中斷就是在計(jì)算機(jī)執(zhí)行程序的過程中,由于出現(xiàn)了某些特殊事情,使得CPU暫停對(duì)程序的執(zhí)行,轉(zhuǎn)而去執(zhí)行處理這一事件的程序。等這些特殊事情處理完之后再回去執(zhí)行之前的程序。中斷一般分為三類:
由計(jì)算機(jī)硬件異常或故障引起的中斷,稱為內(nèi)部異常中斷;
由程序中執(zhí)行了引起中斷的指令而造成的中斷,稱為軟中斷(這也是和我們將要說明的系統(tǒng)調(diào)用相關(guān)的中斷);
由外部設(shè)備請(qǐng)求引起的中斷,稱為外部中斷。簡(jiǎn)單來說,對(duì)中斷的理解就是對(duì)一些特殊事情的處理。
與中斷緊密相連的一個(gè)概念就是中斷處理程序了。當(dāng)中斷發(fā)生的時(shí)候,系統(tǒng)需要去對(duì)中斷進(jìn)行處理,對(duì)這些中斷的處理是由操作系統(tǒng)內(nèi)核中的特定函數(shù)進(jìn)行的,這些處理中斷的特定的函數(shù)就是我們所說的中斷處理程序了。
另一個(gè)與中斷緊密相連的概念就是中斷的優(yōu)先級(jí)。中斷的優(yōu)先級(jí)說明的是當(dāng)一個(gè)中斷正在被處理的時(shí)候,處理器能接受的中斷的級(jí)別。中斷的優(yōu)先級(jí)也表明了中斷需要被處理的緊急程度。每個(gè)中斷都有一個(gè)對(duì)應(yīng)的優(yōu)先級(jí),當(dāng)處理器在處理某一中斷的時(shí)候,只有比這個(gè)中斷優(yōu)先級(jí)高的中斷可以被處理器接受并且被處理。優(yōu)先級(jí)比這個(gè)當(dāng)前正在被處理的中斷優(yōu)先級(jí)要低的中斷將會(huì)被忽略。
典型的中斷優(yōu)先級(jí)如下所示:
機(jī)器錯(cuò)誤 > 時(shí)鐘 > 磁盤 > 網(wǎng)絡(luò)設(shè)備 > 終端 > 軟件中斷
在講系統(tǒng)調(diào)用之前,先說下進(jìn)程的執(zhí)行在系統(tǒng)上的兩個(gè)級(jí)別:用戶級(jí)和核心級(jí),也稱為用戶態(tài)和系統(tǒng)態(tài)(user mode and kernel mode)。
用戶空間就是用戶進(jìn)程所在的內(nèi)存區(qū)域,相對(duì)的,系統(tǒng)空間就是操作系統(tǒng)占據(jù)的內(nèi)存區(qū)域。用戶進(jìn)程和系統(tǒng)進(jìn)程的所有數(shù)據(jù)都在內(nèi)存中。處于用戶態(tài)的程序只能訪問用戶空間,而處于內(nèi)核態(tài)的程序可以訪問用戶空間和內(nèi)核空間。
用戶態(tài)切換到內(nèi)核態(tài)的方式如下:
系統(tǒng)調(diào)用:程序的執(zhí)行一般是在用戶態(tài)下執(zhí)行的,但當(dāng)程序需要使用操作系統(tǒng)提供的服務(wù)時(shí),比如說打開某一設(shè)備、創(chuàng)建文件、讀寫文件(這些均屬于系統(tǒng)調(diào)用)等,就需要向操作系統(tǒng)發(fā)出調(diào)用服務(wù)的請(qǐng)求,這就是系統(tǒng)調(diào)用。
異常:當(dāng)CPU在執(zhí)行運(yùn)行在用戶態(tài)下的程序時(shí),發(fā)生了某些事先不可知的異常,這時(shí)會(huì)觸發(fā)由當(dāng)前運(yùn)行進(jìn)程切換到處理此異常的內(nèi)核相關(guān)程序中,也就轉(zhuǎn)到了內(nèi)核態(tài),比如缺頁異常。
外圍設(shè)備的中斷:當(dāng)外圍設(shè)備完成用戶請(qǐng)求的操作后,會(huì)向CPU發(fā)出相應(yīng)的中斷信號(hào),這時(shí)CPU會(huì)暫停執(zhí)行下一條即將要執(zhí)行的指令轉(zhuǎn)而去執(zhí)行與中斷信號(hào)對(duì)應(yīng)的處理程序,如果先前執(zhí)行的指令是用戶態(tài)下的程序,那么這個(gè)轉(zhuǎn)換的過程自然也就發(fā)生了由用戶態(tài)到內(nèi)核態(tài)的切換。比如硬盤讀寫操作完成,系統(tǒng)會(huì)切換到硬盤讀寫的中斷處理程序中執(zhí)行后續(xù)操作等。
用戶態(tài)和核心態(tài)(內(nèi)核態(tài))之間的區(qū)別是什么呢?
權(quán)限不一樣。
用戶態(tài)的進(jìn)程能存取它們自己的指令和數(shù)據(jù),但不能存取內(nèi)核指令和數(shù)據(jù)(或其他進(jìn)程的指令和數(shù)據(jù))。
核心態(tài)下的進(jìn)程能夠存取內(nèi)核和用戶地址某些機(jī)器指令是特權(quán)指令,在用戶態(tài)下執(zhí)行特權(quán)指令會(huì)引起錯(cuò)誤。在系統(tǒng)中內(nèi)核并不是作為一個(gè)與用戶進(jìn)程平行的估計(jì)的進(jìn)程的集合。
15.C++多線程,互斥,同步
同步和互斥
當(dāng)有多個(gè)線程的時(shí)候,經(jīng)常需要去同步(注:同步不是同時(shí)刻)這些線程以訪問同一個(gè)數(shù)據(jù)或資源。例如,假設(shè)有一個(gè)程序,其中一個(gè)線程用于把文件讀到內(nèi)存,而另一個(gè)線程用于統(tǒng)計(jì)文件中的字符數(shù)。當(dāng)然,在把整個(gè)文件調(diào)入內(nèi)存之前,統(tǒng)計(jì)它的計(jì)數(shù)是沒有意義的。但是,由于每個(gè)操作都有自己的線程,操作系統(tǒng)會(huì)把兩個(gè)線程當(dāng)作是互不相干的任務(wù)分別執(zhí)行,這樣就可能在沒有把整個(gè)文件裝入內(nèi)存時(shí)統(tǒng)計(jì)字?jǐn)?shù)。為解決此問題,你必須使兩個(gè)線程同步工作。
所謂同步,是指在不同進(jìn)程之間的若干程序片斷,它們的運(yùn)行必須嚴(yán)格按照規(guī)定的某種先后次序來運(yùn)行,這種先后次序依賴于要完成的特定的任務(wù)。如果用對(duì)資源的訪問來定義的話,同步是指在互斥的基礎(chǔ)上(大多數(shù)情況),通過其它機(jī)制實(shí)現(xiàn)訪問者對(duì)資源的有序訪問。在大多數(shù)情況下,同步已經(jīng)實(shí)現(xiàn)了互斥,特別是所有寫入資源的情況必定是互斥的。少數(shù)情況是指可以允許多個(gè)訪問者同時(shí)訪問資源。
所謂互斥,是指散布在不同進(jìn)程之間的若干程序片斷,當(dāng)某個(gè)進(jìn)程運(yùn)行其中一個(gè)程序片段時(shí),其它進(jìn)程就不能運(yùn)行它們之中的任一程序片段,只能等到該進(jìn)程運(yùn)行完這個(gè)程序片段后才可以運(yùn)行。如果用對(duì)資源的訪問來定義的話,互斥某一資源同時(shí)只允許一個(gè)訪問者對(duì)其進(jìn)行訪問,具有唯一性和排它性。但互斥無法限制訪問者對(duì)資源的訪問順序,即訪問是無序的。
多線程同步和互斥有幾種實(shí)現(xiàn)方法
線程間的同步方法大體可分為兩類:用戶模式和內(nèi)核模式。顧名思義,內(nèi)核模式就是指利用系統(tǒng)內(nèi)核對(duì)象的單一性來進(jìn)行同步,使用時(shí)需要切換內(nèi)核態(tài)與用戶態(tài),而用戶模式就是不需要切換到內(nèi)核態(tài),只在用戶態(tài)完成操作。
用戶模式下的方法有:原子操作(例如一個(gè)單一的全局變量),臨界區(qū)。
內(nèi)核模式下的方法有:事件,信號(hào)量,互斥量。
1、臨界區(qū):通過對(duì)多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數(shù)據(jù)訪問。
2、互斥量:為協(xié)調(diào)共同對(duì)一個(gè)共享資源的單獨(dú)訪問而設(shè)計(jì)的。
3、信號(hào)量:為控制一個(gè)具有有限數(shù)量用戶資源而設(shè)計(jì)。
4、事 件:用來通知線程有一些事件已發(fā)生,從而啟動(dòng)后繼任務(wù)的開始。
16.邏輯地址 Vs 物理地址 Vs 虛擬內(nèi)存
所謂的邏輯地址,是指計(jì)算機(jī)用戶(例如程序開發(fā)者),看到的地址。例如,當(dāng)創(chuàng)建一個(gè)長(zhǎng)度為100的整型數(shù)組時(shí),操作系統(tǒng)返回一個(gè)邏輯上的連續(xù)空間:指針指向數(shù)組第一個(gè)元素的內(nèi)存地址。由于整型元素的大小為4個(gè)字節(jié),故第二個(gè)元素的地址時(shí)起始地址加4,以此類推。事實(shí)上,邏輯地址并不一定是元素存儲(chǔ)的真實(shí)地址,即數(shù)組元素的物理地址(在內(nèi)存條中所處的位置),并非是連續(xù)的,只是操作系統(tǒng)通過地址映射,將邏輯地址映射成連續(xù)的,這樣更符合人們的直觀思維。
另一個(gè)重要概念是虛擬內(nèi)存。操作系統(tǒng)讀寫內(nèi)存的速度可以比讀寫磁盤的速度快幾個(gè)量級(jí)。但是,內(nèi)存價(jià)格也相對(duì)較高,不能大規(guī)模擴(kuò)展。于是,操作系統(tǒng)可以通過將部分不太常用的數(shù)據(jù)移出內(nèi)存,“存放到價(jià)格相對(duì)較低的磁盤緩存,以實(shí)現(xiàn)內(nèi)存擴(kuò)展。操作系統(tǒng)還可以通過算法預(yù)測(cè)哪部分存儲(chǔ)到磁盤緩存的數(shù)據(jù)需要進(jìn)行讀寫,提前把這部分?jǐn)?shù)據(jù)讀回內(nèi)存。虛擬內(nèi)存空間相對(duì)磁盤而言要小很多,因此,即使搜索虛擬內(nèi)存空間也比直接搜索磁盤要快。唯一慢于磁盤的可能是,內(nèi)存、虛擬內(nèi)存中都沒有所需要的數(shù)據(jù),最終還需要從硬盤中直接讀取。這就是為什么內(nèi)存和虛擬內(nèi)存中需要存儲(chǔ)會(huì)被重復(fù)讀寫的數(shù)據(jù),否則就失去了緩存的意義。現(xiàn)代計(jì)算機(jī)中有一個(gè)專門的轉(zhuǎn)譯緩沖區(qū)(Translation Lookaside Buffer,TLB),用來實(shí)現(xiàn)虛擬地址到物理地址的快速轉(zhuǎn)換。
與內(nèi)存/虛擬內(nèi)存相關(guān)的還有如下兩個(gè)概念:
1) Resident Set
當(dāng)一個(gè)進(jìn)程在運(yùn)行的時(shí)候,操作系統(tǒng)不會(huì)一次性加載進(jìn)程的所有數(shù)據(jù)到內(nèi)存,只會(huì)加載一部分正在用,以及預(yù)期要用的數(shù)據(jù)。其他數(shù)據(jù)可能存儲(chǔ)在虛擬內(nèi)存,交換區(qū)和硬盤文件系統(tǒng)上。被加載到內(nèi)存的部分就是resident set。
2) Thrashing
由于resident set包含預(yù)期要用的數(shù)據(jù),理想情況下,進(jìn)程運(yùn)行過程中用到的數(shù)據(jù)都會(huì)逐步加載進(jìn)resident set。但事實(shí)往往并非如此:每當(dāng)需要的內(nèi)存頁面(page)不在resident set中時(shí),操作系統(tǒng)必須從虛擬內(nèi)存或硬盤中讀數(shù)據(jù),這個(gè)過程被稱為內(nèi)存頁面錯(cuò)誤(page faults)。當(dāng)操作系統(tǒng)需要花費(fèi)大量時(shí)間去處理頁面錯(cuò)誤的情況就是thrashing。
17.內(nèi)部碎片與外部碎片
在內(nèi)存管理中,內(nèi)部碎片是已經(jīng)被分配出去的的內(nèi)存空間大于請(qǐng)求所需的內(nèi)存空間。
外部碎片是指還沒有分配出去,但是由于大小太小而無法分配給申請(qǐng)空間的新進(jìn)程的內(nèi)存空間空閑塊。
固定分區(qū)存在內(nèi)部碎片,可變式分區(qū)分配會(huì)存在外部碎片;
頁式虛擬存儲(chǔ)系統(tǒng)存在內(nèi)部碎片;段式虛擬存儲(chǔ)系統(tǒng),存在外部碎片
為了有效的利用內(nèi)存,使內(nèi)存產(chǎn)生更少的碎片,要對(duì)內(nèi)存分頁,內(nèi)存以頁為單位來使用,最后一頁往往裝不滿,于是形成了內(nèi)部碎片。
為了共享要分段,在段的換入換出時(shí)形成外部碎片,比如5K的段換出后,有一個(gè)4k的段進(jìn)來放到原來5k的地方,于是形成1k的外部碎片。
18.同步和互斥的區(qū)別
當(dāng)有多個(gè)線程的時(shí)候,經(jīng)常需要去同步這些線程以訪問同一個(gè)數(shù)據(jù)或資源。例如,假設(shè)有一個(gè)程序,其中一個(gè)線程用于把文件讀到內(nèi)存,而另一個(gè)線程用于統(tǒng)計(jì)文件中的字符數(shù)。當(dāng)然,在把整個(gè)文件調(diào)入內(nèi)存之前,統(tǒng)計(jì)它的計(jì)數(shù)是沒有意義的。但是,由于每個(gè)操作都有自己的線程,操作系統(tǒng)會(huì)把兩個(gè)線程當(dāng)作是互不相干的任務(wù)分別執(zhí)行,這樣就可能在沒有把整個(gè)文件裝入內(nèi)存時(shí)統(tǒng)計(jì)字?jǐn)?shù)。為解決此問題,你必須使兩個(gè)線程同步工作。
所謂同步,是指散步在不同進(jìn)程之間的若干程序片斷,它們的運(yùn)行必須嚴(yán)格按照規(guī)定的某種先后次序來運(yùn)行,這種先后次序依賴于要完成的特定的任務(wù)。如果用對(duì)資源的訪問來定義的話,同步是指在互斥的基礎(chǔ)上(大多數(shù)情況),通過其它機(jī)制實(shí)現(xiàn)訪問者對(duì)資源的有序訪問。在大多數(shù)情況下,同步已經(jīng)實(shí)現(xiàn)了互斥,特別是所有寫入資源的情況必定是互斥的。少數(shù)情況是指可以允許多個(gè)訪問者同時(shí)訪問資源。
所謂互斥,是指散布在不同進(jìn)程之間的若干程序片斷,當(dāng)某個(gè)進(jìn)程運(yùn)行其中一個(gè)程序片段時(shí),其它進(jìn)程就不能運(yùn)行它們之中的任一程序片段,只能等到該進(jìn)程運(yùn)行完這個(gè)程序片段后才可以運(yùn)行。如果用對(duì)資源的訪問來定義的話,互斥某一資源同時(shí)只允許一個(gè)訪問者對(duì)其進(jìn)行訪問,具有唯一性和排它性。但互斥無法限制訪問者對(duì)資源的訪問順序,即訪問是無序的。
19.什么是線程安全
如果多線程的程序運(yùn)行結(jié)果是可預(yù)期的,而且與單線程的程序運(yùn)行結(jié)果一樣,那么說明是“線程安全”的。
20.同步與異步
同步:
同步的定義:是指一個(gè)進(jìn)程在執(zhí)行某個(gè)請(qǐng)求的時(shí)候,若該請(qǐng)求需要一段時(shí)間才能返回信息,那么,這個(gè)進(jìn)程將會(huì)一直等待下去,直到收到返回信息才繼續(xù)執(zhí)行下去。
特點(diǎn):
同步是阻塞模式;
同步是按順序執(zhí)行,執(zhí)行完一個(gè)再執(zhí)行下一個(gè),需要等待,協(xié)調(diào)運(yùn)行;
異步:
是指進(jìn)程不需要一直等下去,而是繼續(xù)執(zhí)行下面的操作,不管其他進(jìn)程的狀態(tài)。當(dāng)有消息返回時(shí)系統(tǒng)會(huì)通知進(jìn)程進(jìn)行處理,這樣可以提高執(zhí)行的效率。
特點(diǎn):
異步是非阻塞模式,無需等待;
異步是彼此獨(dú)立,在等待某事件的過程中,繼續(xù)做自己的事,不需要等待這一事件完成后再工作。線程是異步實(shí)現(xiàn)的一個(gè)方式。
同步與異步的優(yōu)缺點(diǎn):
同步可以避免出現(xiàn)死鎖,讀臟數(shù)據(jù)的發(fā)生。一般共享某一資源的時(shí)候,如果每個(gè)人都有修改權(quán)限,同時(shí)修改一個(gè)文件,有可能使一個(gè)讀取另一個(gè)人已經(jīng)刪除了內(nèi)容,就會(huì)出錯(cuò),同步就不會(huì)出錯(cuò)。但,同步需要等待資源訪問結(jié)束,浪費(fèi)時(shí)間,效率低。
異步可以提高效率,但,安全性較低。
21.系統(tǒng)調(diào)用與庫函數(shù)的區(qū)別
系統(tǒng)調(diào)用(System call)是程序向系統(tǒng)內(nèi)核請(qǐng)求服務(wù)的方式。可以包括硬件相關(guān)的服務(wù)(例如,訪問硬盤等),或者創(chuàng)建新進(jìn)程,調(diào)度其他進(jìn)程等。系統(tǒng)調(diào)用是程序和操作系統(tǒng)之間的重要接口。
庫函數(shù):把一些常用的函數(shù)編寫完放到一個(gè)文件里,編寫應(yīng)用程序時(shí)調(diào)用,這是由第三方提供的,發(fā)生在用戶地址空間。
在移植性方面,不同操作系統(tǒng)的系統(tǒng)調(diào)用一般是不同的,移植性差;而在所有的ANSI C編譯器版本中,C庫函數(shù)是相同的。
在調(diào)用開銷方面,系統(tǒng)調(diào)用需要在用戶空間和內(nèi)核環(huán)境間切換,開銷較大;而庫函數(shù)調(diào)用屬于“過程調(diào)用”,開銷較小。
22.守護(hù)、僵尸、孤兒進(jìn)程的概念
守護(hù)進(jìn)程:運(yùn)行在后臺(tái)的一種特殊進(jìn)程,獨(dú)立于控制終端并周期性地執(zhí)行某些任務(wù)。
僵尸進(jìn)程:一個(gè)進(jìn)程 fork 子進(jìn)程,子進(jìn)程退出,而父進(jìn)程沒有wait/waitpid子進(jìn)程,那么子進(jìn)程的進(jìn)程描述符仍保存在系統(tǒng)中,這樣的進(jìn)程稱為僵尸進(jìn)程。
孤兒進(jìn)程:一個(gè)父進(jìn)程退出,而它的一個(gè)或多個(gè)子進(jìn)程還在運(yùn)行,這些子進(jìn)程稱為孤兒進(jìn)程。(孤兒進(jìn)程將由 init 進(jìn)程收養(yǎng)并對(duì)它們完成狀態(tài)收集工作)
23.Semaphore(信號(hào)量) Vs Mutex(互斥鎖)
當(dāng)用戶創(chuàng)立多個(gè)線程/進(jìn)程時(shí),如果不同線程/進(jìn)程同時(shí)讀寫相同的內(nèi)容,則可能造成讀寫錯(cuò)誤,或者數(shù)據(jù)不一致。此時(shí),需要通過加鎖的方式,控制臨界區(qū)(critical section)的訪問權(quán)限。對(duì)于semaphore而言,在初始化變量的時(shí)候可以控制允許多少個(gè)線程/進(jìn)程同時(shí)訪問一個(gè)臨界區(qū),其他的線程/進(jìn)程會(huì)被堵塞,直到有人解鎖。
Mutex相當(dāng)于只允許一個(gè)線程/進(jìn)程訪問的semaphore。此外,根據(jù)實(shí)際需要,人們還實(shí)現(xiàn)了一種讀寫鎖(read-write lock),它允許同時(shí)存在多個(gè)閱讀者(reader),但任何時(shí)候至多只有一個(gè)寫者(writer),且不能于讀者共存。
24.IO多路復(fù)用
IO多路復(fù)用是指內(nèi)核一旦發(fā)現(xiàn)進(jìn)程指定的一個(gè)或者多個(gè)IO條件準(zhǔn)備讀取,它就通知該進(jìn)程。IO多路復(fù)用適用如下場(chǎng)合:
當(dāng)客戶處理多個(gè)描述字時(shí)(一般是交互式輸入和網(wǎng)絡(luò)套接口),必須使用I/O復(fù)用。
當(dāng)一個(gè)客戶同時(shí)處理多個(gè)套接口時(shí),而這種情況是可能的,但很少出現(xiàn)。
如果一個(gè)TCP服務(wù)器既要處理監(jiān)聽套接口,又要處理已連接套接口,一般也要用到I/O復(fù)用。
如果一個(gè)服務(wù)器即要處理TCP,又要處理UDP,一般要使用I/O復(fù)用。
如果一個(gè)服務(wù)器要處理多個(gè)服務(wù)或多個(gè)協(xié)議,一般要使用I/O復(fù)用。
與多進(jìn)程和多線程技術(shù)相比,I/O多路復(fù)用技術(shù)的最大優(yōu)勢(shì)是系統(tǒng)開銷小,系統(tǒng)不必創(chuàng)建進(jìn)程/線程,也不必維護(hù)這些進(jìn)程/線程,從而大大減小了系統(tǒng)的開銷。
25.線程安全
如果你的代碼所在的進(jìn)程中有多個(gè)線程在同時(shí)運(yùn)行,而這些線程可能會(huì)同時(shí)運(yùn)行這段代碼。如果每次運(yùn)行結(jié)果和單線程運(yùn)行的結(jié)果是一樣的,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的。或者說:一個(gè)類或者程序所提供的接口對(duì)于線程來說是原子操作或者多個(gè)線程之間的切換不會(huì)導(dǎo)致該接口的執(zhí)行結(jié)果存在二義性,也就是說我們不用考慮同步的問題。
線程安全問題都是由全局變量及靜態(tài)變量引起的。
若每個(gè)線程中對(duì)全局變量、靜態(tài)變量只有讀操作,而無寫操作,一般來說,這個(gè)全局變量是線程安全的;若有多個(gè)線程同時(shí)執(zhí)行寫操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。
26.線程共享資源和獨(dú)占資源問題
一個(gè)進(jìn)程中的所有線程共享該進(jìn)程的地址空間,但它們有各自獨(dú)立的(/私有的)棧(stack),Windows線程的缺省堆棧大小為1M。堆(heap)的分配與棧有所不同,一般是一個(gè)進(jìn)程有一個(gè)C運(yùn)行時(shí)堆,這個(gè)堆為本進(jìn)程中所有線程共享,windows進(jìn)程還有所謂進(jìn)程默認(rèn)堆,用戶也可以創(chuàng)建自己的堆。
用操作系統(tǒng)術(shù)語,線程切換的時(shí)候?qū)嶋H上切換的是一個(gè)可以稱之為線程控制塊的結(jié)構(gòu)(TCB),里面保存所有將來用于恢復(fù)線程環(huán)境必須的信息,包括所有必須保存的寄存器集,線程的狀態(tài)等。
堆: 是大家共有的空間,分全局堆和局部堆。全局堆就是所有沒有分配的空間,局部堆就是用戶分配的空間。堆在操作系統(tǒng)對(duì)進(jìn)程初始化的時(shí)候分配,運(yùn)行過程中也可以向系統(tǒng)要額外的堆,但是記得用完了要還給操作系統(tǒng),要不然就是內(nèi)存泄漏。
棧:是個(gè)線程獨(dú)有的,保存其運(yùn)行狀態(tài)和局部自動(dòng)變量的。棧在線程開始的時(shí)候初始化,每個(gè)線程的棧互相獨(dú)立,因此,棧是 thread safe的。操作系統(tǒng)在切換線程的時(shí)候會(huì)自動(dòng)的切換棧,就是切換 SS/ESP寄存器。棧空間不需要在高級(jí)語言里面顯式的分配和釋放。
總結(jié)
以上是生活随笔為你收集整理的操作系统饥饿现象_操作系统常见面试题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rust为什么显示不了国服_AWS偏爱R
- 下一篇: mysql 临时表增加主键_MySQL之