【操作系統(tǒng),進程,多線程】


1.內(nèi)存的頁面置換算法 ??

(1)最佳置換算法(OPT)(理想置換算法):從主存中移出永遠不再需要的頁面;如無這樣的頁面存在,則選擇最長時間不需要訪問的頁面。于所選擇的被淘汰頁面將是以后永不使用的,或者是在最長時間內(nèi)不再被訪問的頁面,這樣可以保證獲得最低的缺頁率。

(2)先進先出置換算法(FIFO):是最簡單的頁面置換算法。這種算法的基本思想是:當需要淘汰一個頁面時,總是選擇駐留主存時間最長的頁面進行淘汰,即先進入主存的頁面先淘汰。其理由是:最早調(diào)入主存的頁面不再被使用的可能性最大。

(3)最近最久未使用(LRU)算法:這種算法的基本思想是:利用局部性原理,根據(jù)一個作業(yè)在執(zhí)行過程中過去的頁面訪問歷史來推測未來的行為。它認為過去一段時間里不曾被訪問過的頁面,在最近的將來可能也不會再被訪問。所以,這種算法的實質(zhì)是:當需要淘汰一個頁面時,總是選擇在最近一段時間內(nèi)最久不用的頁面予以淘汰。?

(4)時鐘(CLOCK)置換算法:LRU算法的性能接近于OPT,但是實現(xiàn)起來比較困難,且開銷大;FIFO算法實現(xiàn)簡單,但性能差。所以操作系統(tǒng)的設(shè)計者嘗試了很多算法,試圖用比較小的開銷接近LRU的性能,這類算法都是CLOCK算法的變體。

操作系統(tǒng)之頁面置換算法 - fkissx - 博客園

? 2.進程調(diào)度算法? ?

1.先來先服務和短作業(yè)(進程)優(yōu)先調(diào)度算法

(1)先來先服務調(diào)度算法

? ? ?? 按照進程變?yōu)榫途w狀態(tài)的先后次序,分派CPU;

  當前進程占用CPU,直到執(zhí)行完或阻塞,才出讓CPU(非搶占方式)。

  在進程喚醒后(如I/O完成),并不立即恢復執(zhí)行,通常等到當前作業(yè)或進程出讓CPU。

? ? ? 適用場景

  比較有利于長作業(yè),而不利于短作業(yè)。因為長作業(yè)會長時間占據(jù)處理機。

  有利于CPU繁忙的作業(yè),而不利于I/O繁忙的作業(yè)。

(2)短進程優(yōu)先調(diào)度算法

短進程優(yōu)先調(diào)度算法SPF,它們可以分別用于作業(yè)調(diào)度和進程調(diào)度。短作業(yè)優(yōu)先(SJF)的調(diào)度算法是從后備隊列中選擇一個或若干個估計運行時間最短的作業(yè),將它們調(diào)入內(nèi)存運行。而短進程優(yōu)先(SPF)調(diào)度算法則是從就緒隊列中選出一個估計運行時間最短的進程,將處理機分配給它,使它立即執(zhí)行并一直執(zhí)行到完成,或發(fā)生某事件而被阻塞放棄處理機時再重新調(diào)度。主要的不足之處是長作業(yè)的運行得不到保證

2. 高優(yōu)先權(quán)優(yōu)先調(diào)度算法

(1)優(yōu)先權(quán)調(diào)度算法的類型:當用于進程調(diào)度時,該算法是把處理機分配給就緒隊列中優(yōu)先權(quán)最高的進程

(2)高響應比優(yōu)先調(diào)度算法:為每個作業(yè)引入前面所述的動態(tài)優(yōu)先權(quán),并使作業(yè)的優(yōu)先級隨著等待時間的增加而以速率a 提高,則長作業(yè)在等待一定的時間后,必然有機會分配到處理機

3.基于時間片的輪轉(zhuǎn)調(diào)度算法

(1)輪轉(zhuǎn)(round robin。RR)調(diào)度算法:? 在分時系統(tǒng)中,最簡單最常用的是時間片的輪轉(zhuǎn)調(diào)度算法,該算法采用了非常公平的處理機分配方式,即讓就緒隊列上的每個進程僅運行一個時間片。

(2)多級反饋隊列調(diào)度算法: ?

1)、進程在進入待調(diào)度的隊列等待時,首先進入優(yōu)先級最高的Q1等待。  

2)、首先調(diào)度優(yōu)先級高的隊列中的進程。若高優(yōu)先級中隊列中已沒有調(diào)度的進程,則調(diào)度次優(yōu)先級隊列中的進程。例如:Q1,Q2,Q3三個隊列,只有在Q1中沒有進程等待時才去調(diào)度Q2,同理,只有Q1,Q2都為空時才會去調(diào)度Q3。

3)、對于同一個隊列中的各個進程,按照時間片輪轉(zhuǎn)法調(diào)度。比如Q1隊列的時間片為N,那么Q1中的作業(yè)在經(jīng)歷了N個時間片后若還沒有完成,則進入Q2隊列等待,若Q2的時間片用完后作業(yè)還不能完成,一直進入下一級隊列,直至完成。

4)、在低優(yōu)先級的隊列中的進程在運行時,又有新到達的作業(yè),那么在運行完這個時間片后,CPU馬上分配給新到達的作業(yè)(搶占式)。

?3. 進程間通信方式 ??

參考自己文章進程間通信與線程間通信 - 簡書

進程的通信機制主要有:管道、有名管道、消息隊列、信號、信號量、共享內(nèi)存、套接字。

4. 進程,線程 ?

(1)進程是資源的分配和調(diào)度的一個獨立單元,而線程是CPU調(diào)度的基本單元

(2)同一個進程中可以包括多個線程,并且線程共享整個進程的資源(寄存器、堆棧、上下文),一個進程至少包括一個線程。【說一下寄存器,每個線程都有它自己的一組CPU寄存器,稱為線程的上下文。寄存器的作用是暫存指令、數(shù)據(jù)和地址】

(3)進程的創(chuàng)建調(diào)用fork或者vfork,而線程的創(chuàng)建調(diào)用pthread_create,進程結(jié)束后它擁有的所有線程都將銷毀,而線程的結(jié)束不會影響同個進程中的其他線程的結(jié)束

(4)線程是輕量級的進程,它的創(chuàng)建和銷毀所需要的時間比進程小很多,所有操作系統(tǒng)中的執(zhí)行功能都是創(chuàng)建線程去完成的

(5)線程中執(zhí)行時一般都要進行同步和互斥,因為他們共享同一進程的所有資源

(6)線程有自己的私有屬性TCB,線程id,寄存器、硬件上下文,而進程也有自己私有的進程控制塊PCB,這些私有屬性是不被共享的,用來標示一個進程或一個線程的標志 ? ? ?

PCB它記錄了操作系統(tǒng)所需的、用于描述進程的當前狀態(tài)和控制進程的全部信息。包括:

? (1)進程標識信息:用于唯一地標識一個進程,一個進程通常有兩種標識符:內(nèi)部標志符(由操作系統(tǒng)賦予每個進程的一個唯一的數(shù)字標識符)&? 外部標識符(由創(chuàng)建者產(chǎn)生,是由字母和數(shù)字組成的字符串,為用戶進程訪問該進程提供方便。)

(2)處理機狀態(tài):??處理機狀態(tài)信息主要由處理機的各個寄存器內(nèi)的信息組成。進程運行時的許多信息均存放在處理機的各種寄存器中。其中程序狀態(tài)字(PSW)是相當重要的,處理機根據(jù)程序狀態(tài)寄存器中的PSW來控制程序的運行。

(3)進程調(diào)度信息:

? ? ? 1)、進程狀態(tài)。 標識進程的當前狀態(tài)(就緒、運行、阻塞),作為進程調(diào)度的依據(jù)。

? ? ? 2)、 進程優(yōu)先級。 表示進程獲得處理機的優(yōu)先程度。

? ? ?? 3)、為進程調(diào)度算法提供依據(jù)的其他信息。例如,進程等待時間、進程已經(jīng)獲得處理器的總時間和進程占用內(nèi)存的時間等。

? ? ?? 4)、事件。 是指進程由某一狀態(tài)轉(zhuǎn)變?yōu)榱硪粻顟B(tài)所等待發(fā)生的事件。

(4)進程控制信息

? ? ? ? ? ? ?? 1)、程序和數(shù)據(jù)地址。 是指組成進程的程序和數(shù)據(jù)所在內(nèi)存或外存中的首地址,以便在調(diào)度該進程時能從其PCB中找到相應的程序和數(shù)據(jù)。?

? ? ? ? ? ? ?? 2)、進程同步和通信機制。 指實現(xiàn)進程同步和通信時所采取的機制,如消息隊列指針和信號量等,他們可以全部或部分存在PCB中。

? ? ? ? ? ? ?? 3)、資源清單。 列出了進程所需的全部資源?已經(jīng)分配給該進程的資源,但不包括CPU. ? ? ? ?

? ? ? ? ? ? ?? 4)、鏈接指針。它給出了處于同一隊列中的下一個PCB的首地址

總之,操作系統(tǒng)就是根據(jù)進程的PCB來感知進程的存在,并依此對進程進行管理和控制。 PCB是進程存在的唯一標識

進程和線程的應用場景:

1)需要頻繁創(chuàng)建銷毀的優(yōu)先用線程 : ??這種原則最常見的應用就是Web服務器了,來一個連接建立一個線程,斷了就銷毀線程,如果要是用進程,創(chuàng)建和銷毀的代價是很難承受的

2)需要進行大量計算的優(yōu)先使用線程: 所謂大量計算,當然就是要耗費很多CPU,切換頻繁了,這種情況下線程是最合適的。這種原則最常見的是圖像處理、算法處理。

3)可能要擴展到多機分布的用進程,多核分布的用線程

4)強相關(guān)的處理用線程,弱相關(guān)的處理用進程:?什么叫強相關(guān)、弱相關(guān)?理論上很難定義,給個簡單的例子就明白了。一般的Server需要完成如下任務:消息收發(fā)、消息處理?!跋⑹瞻l(fā)”和“消息處理”就是弱相關(guān)的任務,而“消息處理”里面可能又分為“消息解碼”、“業(yè)務處理”,這兩個任務相對來說相關(guān)性就要強多了。因此“消息收發(fā)”和“消息處理”可以分進程設(shè)計,“消息解碼”、“業(yè)務處理”可以分線程設(shè)計。

? ? ? 進程上下文與線程上下文? :

? ? ? 進程上下文:進程的物理實體與支持進程執(zhí)行的物理環(huán)境合稱為進程上下文。? ? ?

? ? ?? 線程上下文:每個線程都有它自己的一組CPU寄存器,稱為線程的上下文

線程上下文切換和進程上下文切換:

線程上下文切換:對線程的上下文進行保存和恢復的過程就被稱為上下文切換。

進程上下文切換:操作系統(tǒng)為了控制進程的執(zhí)行,必須有能力掛起正在CPU上運行的進程,并恢復以前掛起的某個進程的執(zhí)行,這種行為被稱為進程上下文切換

兩者最大的區(qū)別

Linux環(huán)境線程具體介紹:

線程創(chuàng)建及其屬性特點
線程相關(guān)的一些函數(shù)?
設(shè)置線程分離實例


? 5.父子進程、孤兒進程 、僵尸進程 ?

? ?? 父子進程: 通過fork函數(shù)創(chuàng)建的新進程是原進程的子進程,而調(diào)用fork函數(shù)的進程是fork函數(shù)創(chuàng)建出來的新進程的父進程。也就是說,通過fork函數(shù)創(chuàng)建的新進程與原進程是父子關(guān)系,fork就相當于一個憑證,有fork,就有父子關(guān)系。(父子進程永遠共享的東西是(1)文件描述符 (2)內(nèi)存映射區(qū))

? ?? 孤兒進程:一個父進程退出,而它的一個或多個子進程還在運行,那么那些子進程將成為孤兒進程。孤兒進程將被init進程(進程號為1)所收養(yǎng),并由init進程對它們完成狀態(tài)收集工作。(為什么要讓init進行領(lǐng)養(yǎng)呢?因為子進程自己運行結(jié)束后能夠釋放用戶區(qū)空間,但是釋放不了PCB,而PCB只有父進程才能釋放,所以需要個養(yǎng)父。)

  僵尸進程:一個進程使用fork創(chuàng)建子進程,如果子進程退出,而父進程并沒有調(diào)用wait或waitpid去回收子進程資源。這種進程稱之為僵尸進程。

最簡單的父進程回收子進程的方法: wait(NULL);

6.線程有哪幾種狀態(tài)?進程有哪幾種狀態(tài)?

多線程筆試面試概念問答 - CSDN博客

線程有四種狀態(tài):(1)新生狀態(tài)、(2)可運行狀態(tài)、(3)被阻塞狀態(tài)、(4)死亡狀態(tài)

進程有3種狀態(tài):就緒狀態(tài),運行狀態(tài),阻塞狀態(tài)。

也可以說5種(創(chuàng)建,就緒,運行,阻塞,退出)

運行態(tài):進程占用CPU,并在CPU上運行;?

就緒態(tài):進程已經(jīng)具備運行條件,但是CPU還沒有分配過來;?

阻塞態(tài):進程因等待某件事發(fā)生而暫時不能運行;

三種狀態(tài)的進程

7. 線程同步和線程互斥的區(qū)別 ? ? ?

(1)線程同步是指線程之間所具有的一種制約關(guān)系,一個線程的執(zhí)行依賴另一個線程的消息,當它沒有得到另一個線程的消息時應等待,直到消息到達時才被喚醒。 ? ? ??

(2)線程互斥是指對于共享的進程系統(tǒng)資源,在各單個線程訪問時的排它性。當有若干個線程都要使用某一共享資源時,任何時刻最多只允許一個線程去使用,其它要使用該資源的線程必須等待,直到占用資源者釋放該資源。線程互斥可以看成是一種特殊的線程同步

8. 線程同步的方式

Linux:互斥鎖、條件變量和信號量 ? ?Linux 線程同步的三種方法 - CSDN博客

(1)互斥鎖(mutex): 通過鎖機制實現(xiàn)線程間的同步。

? 過程: 初始化鎖(靜態(tài)分配和動態(tài)分配)------>? 加鎖 ? -------> ?解鎖? --------> ??銷毀鎖

初始化互斥鎖,釋放互斥鎖
加互斥鎖實例

(2)條件變量:用來自動阻塞一個線程,直到某特殊情況發(fā)生為止。通常條件變量和互斥鎖同時使用。條件變量分為兩部分: 條件和變量。條件本身是由互斥量保護的。主要包括兩個動作:一個線程等待"條件變量的條件成立"而掛起;另一個線程使"條件成立"(給出條件成立信號)。條件的檢測是在互斥鎖的保護下進行的。如果一個條件為假,一個線程自動阻塞,并釋放等待狀態(tài)改變的互斥鎖。如果另一個線程改變了條件,它發(fā)信號給關(guān)聯(lián)的條件變量,喚醒一個或多個等待它的線程,重新獲得互斥鎖,重新評價條件。如果兩進程共享可讀寫的內(nèi)存,條件變量可以被用來實現(xiàn)這兩進程間的線程同步。

生產(chǎn)者消費者模型中? 條件變量+互斥鎖? 的結(jié)構(gòu)
pthread_cond_wait(&cond,&metux)會對已經(jīng)上鎖的metux解鎖;pthread_cond_signal(&cond)會對metux重新加鎖

過程:初始化條件變量(靜態(tài)初始化和動態(tài)初始化)------> 等待條件成立 -------> ?激活條件變量? ------>? 清除條件變量?

(3)? 信號量(sem)

如同進程一樣,線程也可以通過信號量來實現(xiàn)通信,雖然是輕量級的。信號量函數(shù)的名字都以"sem_"打頭。線程使用的基本信號量函數(shù)有四個。

過程:? 信號量初始化 ------> ?等待信號量 (給信號量減1,然后等待直到信號量的值大于0) ------>釋放信號量 (信號量值加1,并通知其他等待線程 ) ---------->銷毀信號量 ( 我們用完信號量后都它進行清理, 歸還占有的一切資源 )

9. fork進程時的操作

fork()是UNIX操作系統(tǒng)中的一個系統(tǒng)調(diào)用,用于創(chuàng)建新的進程。一個進程,包括代碼、數(shù)據(jù)和分配給進程的資源。

fork()執(zhí)行后通過復制原來進程的地址空間形成新的進程。而父進程和子進程都繼續(xù)執(zhí)行系統(tǒng)調(diào)用fork()之后的指令。

值得一提的是,fork()有兩個返回值,如果是父進程,那么會返回為子進程的進程標識符(非零),而對于子進程,則會返回為0; ??

fork()函數(shù)通過系統(tǒng)調(diào)用創(chuàng)建一個與原來進程幾乎完全相同的進程,也就是兩個進程可以做完全相同的事,但如果初始參數(shù)或者傳入的變量不同,兩個進程也可以做不同的事。

fork系統(tǒng)調(diào)用圖

fork()會產(chǎn)生一個和父進程幾乎完全相同的子進程,但子進程在此后多會exec系統(tǒng)調(diào)用,出于效率考慮,linux中引入了“寫時復制“技術(shù),也就是只有進程空間的各段的內(nèi)容要發(fā)生變化時,才會將父進程的內(nèi)容復制一份給子進程。內(nèi)核只為新生的子進程創(chuàng)建復制于父進程的虛擬空間結(jié)構(gòu)(就是那個4G空間結(jié)構(gòu)),但是不會為該空間分配物理內(nèi)存(包括堆,棧,代碼空間等等),共享父進程的物理內(nèi)存;在fork之后exec之前兩個進程用的是相同的物理空間(內(nèi)存區(qū)),子進程的代碼段、數(shù)據(jù)段、堆棧都是指向父進程的物理空間,也就是說,兩者的虛擬空間(就是那個4G的虛擬內(nèi)存空間)不同,但其對應的物理空間(就是實際的物理內(nèi)存,包括磁盤空間,內(nèi)存等)是同一個。當父子進程中有更改相應段的行為發(fā)生時,再為子進程相應的段分配物理空間,如果不是因為exec,內(nèi)核會給子進程的數(shù)據(jù)段、堆棧段分配相應的物理空間(至此兩者有各自的進程空間,互不影響),而代碼段繼續(xù)共享父進程的物理空間(兩者的代碼完全相同)。而如果是因為exec,由于兩者執(zhí)行的代碼不同,子進程的代碼段也會分配單獨的物理空間。

fork時子進程獲得父進程數(shù)據(jù)空間、堆和棧的復制,所以變量的地址(變量的虛擬地址)也是一樣的,但是虛擬空間不一樣。

子進程也有與父進程不同的屬性:

(1) 進程號,?子進程號不同與任何一個活動的進程組號.

(2) 父進程號.

.(3)子進程繼承父進程的文件描述符或流時,?具有自己的一個拷貝并且與父進程和其它子進程共享該資源.

(4)子進程的用戶時間和系統(tǒng)時間被初始化為0.

(5).?子進程的超時時鐘設(shè)置為0.

(6).?子進程的信號處理函數(shù)指針組置為空.?(該處有問題。)

子進程繼承父進程的處理函數(shù)(當一個進程調(diào)用fork時,因為子進程在開始時復制父進程的存儲映像,信號捕捉函數(shù)的地址在子進程中是有意義的,所以子進程繼承父進程的信號處理函數(shù)。

特殊的是exec,因為exec運行新的程序后會覆蓋從父進程繼承來的存儲映像,那么信號捕捉函數(shù)在新程序中已無意義,所以exec會將原先設(shè)置為要捕捉的信號都更改為默認動作。)

(7).?子進程不繼承父進程的記錄鎖.

exec()函數(shù)族 ? Linux進程 -- exec函數(shù)操作 - CSDN博客

(1)讓父子進程執(zhí)行不相關(guān)的操作

(2)能夠替換進程地址空間中的源代碼段

用fork函數(shù)創(chuàng)建子進程后,子進程往往要調(diào)用一種exec函數(shù)以執(zhí)行另一個程序。當進程調(diào)用一種exec函數(shù)時,該進程執(zhí)行的程序完全替換為新程序,而新程序則從其main函數(shù)開始執(zhí)行。因為調(diào)用exec并不創(chuàng)建新進程,所以前后的進程ID并未改變。exec只是用一個全新的程序替換了當前進程的正文、數(shù)據(jù)、堆和棧段(因為新的代碼段會定義新的棧區(qū),堆區(qū)變量)。

10.fork、vfork以及clone的區(qū)別?

A:從源碼來分析,它們都用來創(chuàng)建linux輕量級進程的,vfork與fork的區(qū)別是,vfork共享父進程的地址空間,vfork之后父進程會讓子進程先運行,因為vfork主要用于為了讓子進程exec(運行),exec之后子進程會用新程序的數(shù)據(jù)將內(nèi)存重新刷一遍,這樣它就有了自己的地址空間。子進程exec之后,會向父進程發(fā)送信號,這個時候父進程就可以開始運行了,如果子進程修改了父進程地址空間的話,父進程喚醒的時候就會發(fā)現(xiàn)自己的數(shù)據(jù)被改了,完整性丟失,所以這是不安全的。clone的話呢,它提供選項,讓你自己選擇每次復制哪些東西,但是它調(diào)用的還是do_fork好像... vfork()系統(tǒng)調(diào)用:

  那么講完了fork(),我們不妨和vfork()比較,并且學習總結(jié)一下vfork(.); ??

vfork也是創(chuàng)建一個子進程,但是子進程共享父進程的空間。在vfork創(chuàng)建子進程之后,父進程阻塞,直到子進程執(zhí)行了exec()或者exit()。vfork最初是因為fork沒有實現(xiàn)COW機制,而很多情況下fork之后會緊接著exec,而exec的執(zhí)行相當于之前fork復制的空間全部變成了無用功,所以設(shè)計了vfork。而現(xiàn)在fork使用了COW機制,唯一的代價僅僅是復制父進程頁表的代價,所以vfork不應該出現(xiàn)在新的代碼之中。vfork創(chuàng)建出來的不是真正意義上的進程,而是一個線程,因為它缺少進程要素(4),獨立的內(nèi)存資源。

? ? ? vfork()在某些情況下,我們知道vfork()與fork()執(zhí)行結(jié)果是一樣的,? 除了子進程會執(zhí)行一次exec系統(tǒng)調(diào)用或者調(diào)用_exit(0)退出. ? 函數(shù)原型:pid_t vfork vfork(void), 具體返回值與其中fork()類似. 這個函數(shù)時是在沒有實現(xiàn)寫時賦值前提下,所以現(xiàn)在我們并不推薦使用vfork().

結(jié)論如下  1)vfork() 子進程與父進程共享數(shù)據(jù)段

? ? ? ? ? ? ? ? ?  2)vfork() 中是子進程先執(zhí)行,父進程后執(zhí)行.

   ? ? ? ? ? ? 通常我們都是與exec函數(shù)在一起,在主進程中替換進程印象.

?clone是Linux為創(chuàng)建線程設(shè)計的(雖然也可以用clone創(chuàng)建進程)。所以可以說clone是fork的升級版本,不僅可以創(chuàng)建進程或者線程,還可以指定創(chuàng)建新的命名空間(namespace)、有選擇的繼承父進程的內(nèi)存、甚至可以將創(chuàng)建出來的進程變成父進程的兄弟進程等等。clone函數(shù)功能強大,帶了眾多參數(shù),因此由他創(chuàng)建的進程要比前面2種方法要復雜。

clone可以讓你有選擇性的繼承父進程的資源,你可以選擇像vfork一樣和父進程共享一個虛內(nèi)存空間,從而使創(chuàng)造的是線程,你也可以不和父進程共享,你甚至可以選擇創(chuàng)造出來的進程和父進程不再是父子關(guān)系,而是兄弟關(guān)系。

clone和fork的區(qū)別:

? ? ?(1) clone和fork的調(diào)用方式很不相同,clone調(diào)用需要傳入一個函數(shù),該函數(shù)在子進程中執(zhí)行。

? ? ? (2)clone和fork最大不同在于clone不再復制父進程的??臻g,而是自己創(chuàng)建一個新的。(void *child_stack,)也就是第二個參數(shù),需要分配棧指針的空間大小,所以它不再是繼承或者復制,而是全新的創(chuàng)造。

11.用戶態(tài)與內(nèi)核態(tài)的切換與區(qū)別

4G地址空間解析圖

(1)內(nèi)核態(tài)和用戶態(tài)的區(qū)別

? ? ?? 當一個任務(進程)執(zhí)行系統(tǒng)調(diào)用而陷入內(nèi)核代碼中執(zhí)行時,我們就稱進程處于內(nèi)核狀態(tài)。此時處理器處于特權(quán)級最高的(0級)內(nèi)核代碼。當進程處于內(nèi)核態(tài)時,執(zhí)行的內(nèi)核代碼會使用當前的內(nèi)核棧。每個進程都有自己的內(nèi)核棧。當進程在執(zhí)行用戶自己的代碼時,則稱其處于用戶態(tài)。即此時處理器在特權(quán)級最低的用戶代碼中運行。

? ? ?? 當正在執(zhí)行用戶程序而突然中斷時,此時用戶程序也可以象征性地處于進程的內(nèi)核態(tài)。因為中斷處理程序?qū)⑹褂卯斍斑M程的內(nèi)核態(tài)。 內(nèi)核態(tài)與用戶態(tài)是操作系統(tǒng)的兩種運行級別,跟intel cpu沒有必然聯(lián)系,intel cpu提供Ring0-Ring3三種級別運行模式,Ring0級別最高,Ring3級別最低。Linux使用了Ring3級別運行用戶態(tài)。Ring0作為內(nèi)核態(tài),沒有使用Ring1和Ring2.Ring3不能訪問Ring0的地址空間,包括代碼和數(shù)量。Linux進程的4GB空間,3G-4G部分大家是共享的,是內(nèi)核態(tài)的地址空間,這里存放在整個內(nèi)核代碼和所有的內(nèi)核模塊,以及內(nèi)核所維護的數(shù)據(jù)。用戶運行一程序,該程序所創(chuàng)建的進程開始是運行在用戶態(tài)的,如果要執(zhí)行文件操作,網(wǎng)絡數(shù)據(jù)發(fā)送等操作,必須通過write,send等系統(tǒng)調(diào)用,這些系統(tǒng)會調(diào)用內(nèi)核中的代碼來完成操作,這時,必須切換到Ring0,然后進入3GB-4GB中的內(nèi)核地址空間去執(zhí)行這些代碼完成操作,完成后,切換Ring3,回到用戶態(tài)。這樣,用戶態(tài)的程序就不能隨意操作1內(nèi)核地址空間,具有一定的安全保護作用。

(2)用戶態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換

用戶態(tài)切換到內(nèi)核態(tài)的3種方式

a.系統(tǒng)調(diào)用

這是用戶進程主動要求切換到內(nèi)核態(tài)的一種方式,用戶進程通過系統(tǒng)調(diào)用申請操作系統(tǒng)提供的服務程序完成工作。而系統(tǒng)調(diào)用的機制其核心還是使用了操作系統(tǒng)為用戶特別開放的一個中斷來實現(xiàn),例如Linux的ine 80h中斷。

b.異常

當CPU在執(zhí)行運行到用戶態(tài)的程序時,發(fā)現(xiàn)了某些事件不可知的異常,這時會觸發(fā)由當前運行進程切換到處理此異常的內(nèi)核相關(guān)程序中,也就到了內(nèi)核態(tài),比如缺頁異常。

c.外圍設(shè)備的中斷

當外圍設(shè)備完成用戶請求的操作之后,會向CPU發(fā)出相應的中斷信號,這時CPU會暫停執(zhí)行下一條將要執(zhí)行的指令轉(zhuǎn)而去執(zhí)行中斷信號的處理程序,如果先執(zhí)行的指令是用戶態(tài)下的程序,那么這個轉(zhuǎn)換的過程自然也就發(fā)生了由用戶態(tài)到內(nèi)核態(tài)的切換。比如硬盤讀寫操作完成,系統(tǒng)會切換到硬盤讀寫的中斷處理程序中執(zhí)行后續(xù)操作等。

12.內(nèi)部碎片和外部碎片

內(nèi)部碎片:內(nèi)部碎片就是已經(jīng)被分配出去(能明確指出屬于哪個進程)卻不能被利用的內(nèi)存空間;是處于(操作系統(tǒng)分配的用于裝載某一進程的內(nèi)存)區(qū)域內(nèi)部的存儲塊。占有這些區(qū)域或頁面的進程并不使用這個存儲塊。而在進程占有這塊存儲塊時,系統(tǒng)無法利用它。直到進程釋放它,或進程結(jié)束時,系統(tǒng)才有可能利用這個存儲塊

外部碎片:外部碎片指的是還沒有被分配出去(不屬于任何進程),但由于太小了無法分配給申請內(nèi)存空間的新進程的內(nèi)存空閑區(qū)域。外部碎片是處于任何兩個已分配區(qū)域或頁面之間的空閑存儲塊。這些存儲塊的總和可以滿足當前申請的長度要求,但是由于它們的地址不連續(xù)或其他原因,使得系統(tǒng)無法滿足當前申請。如圖:

假設(shè)這是一段連續(xù)的頁框,陰影部分表示已經(jīng)被使用的頁框,現(xiàn)在需要申請一個連續(xù)的5個頁框。這個時候,在這段內(nèi)存上不能找到連續(xù)的5個空閑的頁框,就會去另一段內(nèi)存上去尋找5個連續(xù)的頁框,這樣子,久而久之就形成了頁框的浪費。稱為外部碎片。

13. slab分配機制

? ? ? ? slab分配器中用到了對象這個概念,所謂? 對象就是內(nèi)核中的數(shù)據(jù)結(jié)構(gòu)? 以及 ? 對該數(shù)據(jù)結(jié)構(gòu)進行創(chuàng)建和撤銷的操作。它的基本思想是將內(nèi)核中經(jīng)常使用的對象放到高速緩存中,并且由系統(tǒng)保持為初始的可利用狀態(tài)。比如進程描述符,內(nèi)核中會頻繁對此數(shù)據(jù)進行申請和釋放。當一個新進程創(chuàng)建時,內(nèi)核會直接從slab分配器的高速緩存中獲取一個已經(jīng)初始化了的對象;當進程結(jié)束時,該結(jié)構(gòu)所占的頁框并不被釋放,而是重新返回slab分配器中。如果沒有基于對象的slab分 配器,內(nèi)核將花費更多的時間去分配、初始化以及釋放一個對象。

? ? ?? slab分配器為每種對象分配一個高速緩存,這個緩存可以看做是同類型對象的一種儲備。每個高速緩存所占的內(nèi)存區(qū)又被劃分多個slab,每個 slab是由一個或多個連續(xù)的頁框組成。每個頁框中包含若干個對象,既有已經(jīng)分配的對象,也包含空閑的對象。slab分配器的大致組成圖如下:

slab分配器的結(jié)構(gòu)

14. PCB是什么呢?PID是什么?

進程控制塊(PCB):

? ? ? ? 每個進程在內(nèi)核中都有一個進程控制塊(PCB)來維護進程相關(guān)的信息。其作用是使一個在多道程序環(huán)境下不能獨立運行的程序成為一個能獨立運行的基本單位或其他進程并發(fā)執(zhí)行的進程。PCB是系統(tǒng)感知進程存在的唯一標識。Linux內(nèi)核的進程控制塊是task_struct結(jié)構(gòu)體。task_struct是Linux內(nèi)核的一種數(shù)據(jù)結(jié)構(gòu)。它會被裝載到RAM里并且包含著進程的信息。它定義在linux-2.6.38.8、include/linux/sched.h文件中。task_struct結(jié)構(gòu)體包含了以下內(nèi)容:

優(yōu)先級:相對于其他進程的優(yōu)先級。 ? 程序計數(shù)器: 下一句要執(zhí)行的指令地址。

內(nèi)存指針:包括程序代碼和進程相關(guān)數(shù)據(jù)的指針,還有和其他進程共享的內(nèi)存塊的指針。

上下文數(shù)據(jù):進程執(zhí)行時處理器的寄存器中的數(shù)據(jù)。上下文數(shù)據(jù),也稱處理器相關(guān)的環(huán)境信息。進程作為一個執(zhí)行環(huán)境的綜合,當系統(tǒng)調(diào)度某個進程執(zhí)行,即為該進程建立完整的環(huán)境時,處理器的寄存器、堆棧等是必不可少的。因為不同的處理器對內(nèi)部寄存器和堆棧的定義是不盡相同的,所以也叫“處理機狀態(tài)”。當進程暫停時,處理機狀態(tài)必須保存到進程的task_struct結(jié)構(gòu)中,當進程被調(diào)度重新運行時再從中恢復這些環(huán)境,也就是恢復這些寄存器和堆棧的值。

struct thread_struct *tss;? ? //任務切換狀態(tài)

I/O狀態(tài)信息:包括顯示的I/O請求,分配給進程的I/O設(shè)備和被進程使用的文件列表。

記賬信息:又稱會計信息。如CPU與實際時間,使用數(shù)量、時限、賬號、工作或進程號碼。

進程標識符(PID)

? ? ? ? 每個進程都有進程標識符,用戶標識符,組標識符。內(nèi)核通過這個標識符來識別不同的進程,同時,PID也是內(nèi)核提供給用戶程序的接口,用戶通過PID對進程發(fā)號施令。PID是32位的無符號整數(shù),他被順序編號:新創(chuàng)建進程的PID通常是前一個進程的PID加1,然而,為了與16位硬件平臺的傳統(tǒng)Linux系統(tǒng)保持兼容,在Linux上允許的最大PID是32767,當內(nèi)核在系統(tǒng)中創(chuàng)建第32768個進程時,就必須重新開始使用已閑置的PID。即最多可運行32767個進程。

15.內(nèi)存分配

C++內(nèi)存管理(超長,例子很詳細,排版很好) - CSDN博客

生長方向:對于堆來講,生長方向是向上的,也就是向著內(nèi)存地址增加的方向;對于棧來講,它的生長方向是向下的,是向著內(nèi)存地址減小的方向增長。

16.頁和段的區(qū)別,哪些對程序員可見?(進一步了解一下分頁和分段)

詳細看 ? ??段和頁區(qū)別 - CSDN博客 ? ? ?操作系統(tǒng)之分頁分段介紹 - CSDN博客

區(qū)別:(1)頁是信息的物理單位,分頁是為實現(xiàn)離散分配方式,以消減內(nèi)存的外零頭,提高內(nèi)存的利用率;或者說,分頁僅僅是由于系統(tǒng)管理的需要,而不是用戶的需要。段是信息的邏輯單位,它含有一組其意義相對完整的信息。分段的目的是為了能更好的滿足用戶的需要。

? ? ? ? ? (2)頁的大小固定且由系統(tǒng)確定,把邏輯地址劃分為頁號和頁內(nèi)地址兩部分,是由機器硬件實現(xiàn)的,因而一個系統(tǒng)只能有一種大小的頁面。 段的長度卻不固定,決定于用戶所編寫的程序,通常由編輯程序在對源程序進行編輯時,根據(jù)信息的性質(zhì)來劃分。

? ? ? ?? (3)分頁的作業(yè)地址空間是維一的,即單一的線性空間,程序員只須利用一個記憶符,即可表示一地址。 分段的作業(yè)地址空間是二維的,程序員在標識一個地址時,既需給出段名,又需給出段內(nèi)地址。

分頁:操作系統(tǒng)以內(nèi)存頁為單位管理內(nèi)存,將虛擬內(nèi)存空間和物理內(nèi)存空間皆劃分為大小相同的頁面,如4KB、8KB或16KB等,并以頁面作為內(nèi)存空間的最小分配單位,一個程序的一個頁面可以存放在任意一個物理頁面里。

?? 分段通常對程序員而言是可見的, 而分頁對程序員而言是不可見的


17.虛擬內(nèi)存(也叫虛擬存儲器)計算機底層知識拾遺(一)理解虛擬內(nèi)存機制 - CSDN博客

虛擬內(nèi)存(虛擬地址, 頁表,換頁...) - joannae - 博客園 ? (虛擬地址轉(zhuǎn)換物理地址比較詳細)

虛擬內(nèi)存:是計算機系統(tǒng)內(nèi)存管理的一種技術(shù),它使得應用程序認為它擁有連續(xù)的可用的內(nèi)存(一個連續(xù)完整的地址空間),而實際上,它通常是被分隔成多個物理內(nèi)存碎片,還有部分暫時存儲在外部磁盤存儲器上,在需要時進行數(shù)據(jù)交換。對虛擬內(nèi)存的定義是基于對地址空間的重定義的,即把地址空間定義為“連續(xù)的虛擬內(nèi)存地址”,以借此“欺騙”程序,使它們以為自己正在使用一大塊的“連續(xù)”地址。

虛擬內(nèi)存的基本思想是,每個進程有用獨立的邏輯地址空間,內(nèi)存被分為大小相等的多個塊,稱為頁(Page).每個頁都是一段連續(xù)的地址。對于進程來看,邏輯上貌似有很多內(nèi)存空間,其中一部分對應物理內(nèi)存上的一塊(稱為頁框,通常頁和頁框大小相等),還有一些沒加載在內(nèi)存中的對應在硬盤上,

虛擬內(nèi)存和物理內(nèi)存以及磁盤的映射關(guān)系

從圖中看出,虛擬內(nèi)存實際上可以比物理內(nèi)存大。當訪問虛擬內(nèi)存時,會訪問MMU(內(nèi)存管理單元)去匹配對應的物理地址(比如圖5的0,1,2),而如果虛擬內(nèi)存的頁并不存在于物理內(nèi)存中(如圖的3,4),會產(chǎn)生缺頁中斷,從磁盤中取得缺的頁放入內(nèi)存,如果內(nèi)存已滿,還會根據(jù)某種算法將磁盤中的頁換出。

MMU:內(nèi)存管理單元,它是中央處理器(CPU)中用來管理虛擬存儲器、物理存儲器的控制線路,同時也負責虛擬地址映射為物理地址,以及提供硬件機制的內(nèi)存訪問授權(quán),多用戶多進程操作系統(tǒng)。

CPU把虛擬地址轉(zhuǎn)換成物理地址:一個虛擬地址,大小4個字節(jié)(32bit),分為3個部分:第22位到第31位這10位(最高10位)是頁目錄中的索引,第12位到第21位這10位是頁表中的索引,第0位到第11位這12位(低12位)是頁內(nèi)偏移。一個一級頁表有1024項,虛擬地址最高的10bit剛好可以索引1024項(2的10次方等于1024)。一個二級頁表也有1024項,虛擬地址中間部分的10bit,剛好索引1024項。虛擬地址最低的12bit(2的12次方等于4096),作為頁內(nèi)偏移,剛好可以索引4KB,也就是一個物理頁中的每個字節(jié)。

虛擬內(nèi)存技術(shù)的實現(xiàn)?

虛擬內(nèi)存中,允許將一個作業(yè)分多次調(diào)入內(nèi)存。釆用連續(xù)分配方式時,會使相當一部分內(nèi)存空間都處于暫時或“永久”的空閑狀態(tài),造成內(nèi)存資源的嚴重浪費,而且也無法從邏輯上擴大內(nèi)存容量。因此,虛擬內(nèi)存的實需要建立在離散分配的內(nèi)存管理方式的基礎(chǔ)上。虛擬內(nèi)存的實現(xiàn)有以下三種方式:?

1)請求分頁存儲管理。? 2)請求分段存儲管理。? 3)請求段頁式存儲管理。?

不管哪種方式,都需要有一定的硬件支持。一般需要的支持有以下幾個方面:?

1)一定容量的內(nèi)存和外存。?

2)頁表機制(或段表機制),作為主要的數(shù)據(jù)結(jié)構(gòu)。?

3)中斷機制,當用戶程序要訪問的部分尚未調(diào)入內(nèi)存,則產(chǎn)生中斷。?

4)地址變換機制,邏輯地址到物理地址的變換。

邏輯地址,物理地址,虛擬地址

邏輯地址空間:邏輯地址空間是指一個源程序在編譯或者連接裝配后指令和數(shù)據(jù)所用的所有相對地址的空間。它是作業(yè)進入內(nèi)存,其程序、數(shù)據(jù)在內(nèi)存中定位的參數(shù)。程序經(jīng)過編譯后,每個目標模塊都是從0號單元開始編址,稱為該目標模塊的邏輯地址(也叫相對地址)

物理地址空間:物理地址空間是指內(nèi)存中物理單元的集合,它是地址轉(zhuǎn)換的最終地址,進程在運行時執(zhí)行指令和訪問數(shù)據(jù)都要通過物理地址從主存中存取。

虛擬地址: 4G虛擬地址空間中的地址,程序中使用的都是虛擬地址

虛擬尋址 (虛擬地址和物理地址之間轉(zhuǎn)換)

使用虛擬尋址,CPU通過生成一個虛擬地址來訪問主存,這個虛擬地址在被送到內(nèi)存之前會被內(nèi)存管理單元(MMU)轉(zhuǎn)換成合適的物理地址,從而找到目標地址。具體過程如下圖

虛擬內(nèi)存工作機制:

1).在正常使用的時候,系統(tǒng)內(nèi)部的交換(緩存)文件通常保存在虛擬內(nèi)存中;

2).自動把非活動的系統(tǒng)進程或者程序映射到虛擬空間;

3).當物理內(nèi)存低于25%左右的時候,則把虛擬內(nèi)存和物理內(nèi)存合并,也就是說系統(tǒng)此時會把你的虛擬內(nèi)存也識別成物理內(nèi)存。

當虛擬內(nèi)存設(shè)置的比物理內(nèi)存還要大的時候,會導致系統(tǒng)提前使用你的虛擬空間,這會使你感覺的系統(tǒng)的速度下降,同時硬盤負擔大大加重。(因為cpu的訪問順序是高速緩存到內(nèi)存再到硬盤(虛擬內(nèi)存實際就是硬盤存儲空間),所以注定硬盤傳輸?shù)乃俣缺葍?nèi)存延遲,而且由于內(nèi)部運行機制的不同,內(nèi)存的內(nèi)部運行速度遠遠快于硬盤)

虛擬內(nèi)存的好處:

第一,使用虛擬地址可以更加高效的使用物理內(nèi)存。在計算機系統(tǒng)中物理內(nèi)存是有限的,對于一般的計算機來說,物理內(nèi)存一般為4G或者8G. 對于現(xiàn)代多任務的通用系統(tǒng)來說這顯然是不夠的。試想假如我們需要看一個4G大小以上的視頻,這時物理內(nèi)存就不夠了。在存在虛擬地址的情況下,可以為每個程序分配足夠大小的虛擬地址空間,但是這些地址空間在一開始并沒有真正的對應物理地址,而是在真正使用的時候才去對應。這樣在訪問后邊的地址空間的時候就可以將前邊當前沒有在訪問的物理頁釋放掉,或者交換到硬盤中。這樣這個物理頁又可以去對應新的虛擬地址。從而使物理內(nèi)存可以充分的利用。

第二,使用虛擬地址可以使內(nèi)存的管理更加便捷。在程序編譯的時候就會生成虛擬地址,對于不同的機器或者對于同一臺機器的不同時間,該虛擬地址可以對應不同的物理頁。試想,如果沒有虛擬地址,那么編譯時產(chǎn)生的物理地址在某些機器上可能已經(jīng)被占用而不能訪問。從而導致程序需要重新編譯。

第三,為了安全性的考慮。在使用虛擬地址的時候,暴露給程序員永遠都是虛擬地址,而具體的物理地址在哪里,這個只有系統(tǒng)才了解。這樣就提高了系統(tǒng)的封裝性。

第四,虛擬內(nèi)存讓每個進程有獨立的地址空間,對于私有區(qū)域來說,當不同進程對該區(qū)域做修改時,會觸發(fā)寫時拷貝,為新進程維護私有的虛擬地址空間。

18. Linux父進程怎么知道子進程結(jié)束了

當子進程退出的時候,內(nèi)核會向父進程發(fā)送SIGCHLD(sigchld)信號,子進程的退出是個異步事件(子進程可以在父進程運行的任何時刻終止)

如果不想讓子進程變成僵尸進程可在父進程中加入:signal(SIGCHLD,SIG_IGN);

如果將此信號的處理方式設(shè)為忽略,可讓內(nèi)核把僵尸子進程轉(zhuǎn)交給init進程去處理,省去了大量僵尸進程占用系統(tǒng)資源。

19.?守護進程及其創(chuàng)建過程

? ?? 守護進程(Daemon):是運行在后臺的一種特殊進程,它獨立于控制終端并且周期性地執(zhí)行某種任務或等待處理某些發(fā)生的事件。它不需要用戶輸入就能運行而且提供某種服務,不是對整個系統(tǒng)就是對某個用戶程序提供服務。 ? ? ? ? ??

Linux系統(tǒng)的大多數(shù)服務器就是通過守護進程實現(xiàn)的。常見的守護進程包括系統(tǒng)日志進程syslogd、 web服務器httpd郵件服務器sendmail數(shù)據(jù)庫服務器mysqld等。

守護進程的父進程是init進程,因為它真正的父進程在fork出子進程后就先于子進程exit退出了,所以它是一個由init繼承的孤兒進程。

Linux下完全可以利用 daemon() 函數(shù)創(chuàng)建守護進程,其函數(shù)原型

函數(shù)daemon接收兩個參數(shù):

  nochdir:? 如果是0,將當前工作目錄切換到根目錄"/",否則工作目錄不改變。

  noclose:? 如果是0,將0(標準輸入),1(標準輸出),2(標準錯誤)重定向到/dev/null,否則不變。

守護進程的創(chuàng)建過程:【Linux編程】守護進程(daemon)詳解與創(chuàng)建 - CSDN博客


(1)設(shè)置工作目錄(不是必須),重設(shè)文件權(quán)限掩碼(不是必須),關(guān)閉文件描述符(不是必須),其他的步驟都是必須的;(2)第一次創(chuàng)建子進程讓父進程退出時為了讓子進程創(chuàng)建新會話(因為當進程是會話組長時setsid()調(diào)用失敗,父進程可能是會話組長,子進程則一定不是),第二次父進程退出時為了讓子進程不能重新打開控制終端;

(1)fork()創(chuàng)建子進程,父進程exit()退出

這是創(chuàng)建守護進程的第一步。由于守護進程是脫離控制終端的,因此,完成第一步后就會在Shell終端里造成程序已經(jīng)運行完畢的假象。之后的所有工作都在子進程中完成,而用戶在Shell終端里則可以執(zhí)行其他命令,從而在形式上做到了與控制終端的脫離,在后臺工作。

(2)在子進程中調(diào)用 setsid() 函數(shù)創(chuàng)建新的會話

在調(diào)用了 fork() 函數(shù)后,子進程全盤拷貝了父進程的會話期、進程組、控制終端等,雖然父進程退出了,但會話期、進程組、控制終端等并沒有改變,因此,這還不是真正意義上的獨立開來,而 setsid() 函數(shù)能夠使進程完全獨立出來。

(3)再次 fork() 一個子進程并讓父進程退出。

現(xiàn)在,進程已經(jīng)成為無終端的會話組長,但它可以重新申請打開一個控制終端,可以通過 fork() 一個子進程,該子進程不是會話首進程,該進程將不能重新打開控制終端。退出父進程。

(4)在子進程中調(diào)用 chdir() 函數(shù),讓根目錄 ”/” 成為子進程的工作目錄

這一步也是必要的步驟。使用fork創(chuàng)建的子進程繼承了父進程的當前工作目錄。由于在進程運行中,當前目錄所在的文件系統(tǒng)(如“/mnt/usb”)是不能卸載的,這對以后的使用會造成諸多的麻煩(比如系統(tǒng)由于某種原因要進入單用戶模式)。因此,通常的做法是讓"/"作為守護進程的當前工作目錄,這樣就可以避免上述的問題,當然,如有特殊需要,也可以把當前工作目錄換成其他的路徑,如/tmp。改變工作目錄的常見函數(shù)是chdir。

(5)在子進程中調(diào)用 umask() 函數(shù),設(shè)置進程的文件權(quán)限掩碼為0 ??Linux下的權(quán)限掩碼umask - Mr_listening - 博客園

文件權(quán)限掩碼是指屏蔽掉文件權(quán)限中的對應位。比如,有個文件權(quán)限掩碼是050,它就屏蔽了文件組擁有者的可讀與可執(zhí)行權(quán)限。由于使用fork函數(shù)新建的子進程繼承了父進程的文件權(quán)限掩碼,這就給該子進程使用文件帶來了諸多的麻煩。因此,把文件權(quán)限掩碼設(shè)置為0,可以大大增強該守護進程的靈活性。設(shè)置文件權(quán)限掩碼的函數(shù)是umask。在這里,通常的使用方法為umask(0)。

語法格式:::?umask?預設(shè)掩碼數(shù)值???使用說明:::建立文件和文件夾的時候預設(shè)的掩碼權(quán)限(你將要去掉的權(quán)限數(shù)值表達)???主要參數(shù):::??-S?以文字的方式來表示權(quán)限掩碼???應用實例:::??(1)設(shè)要生成的文件以rw-?r--?r--這樣的權(quán)限字出現(xiàn)??umask?133?(相當于777-644=133)??(2)設(shè)要生成的目錄權(quán)限以rwxr-xr-x這樣的權(quán)限字出現(xiàn)??umask?022?(相當于777-055=022) ? ?? (r、w、x分別是4、2、1)? 目錄基數(shù)是777,文件基數(shù)是666 ??

umask 后面跟的是被拿走的權(quán)限值

(6)在子進程中關(guān)閉任何不需要的文件描述符

同文件權(quán)限碼一樣,用fork函數(shù)新建的子進程會從父進程那里繼承一些已經(jīng)打開了的文件。這些被打開的文件可能永遠不會被守護進程讀寫,但它們一樣消耗系統(tǒng)資源,而且可能導致所在的文件系統(tǒng)無法卸下。在上面的第二步之后,守護進程已經(jīng)與所屬的控制終端失去了聯(lián)系。因此從終端輸入的字符不可能達到守護進程,守護進程中用常規(guī)方法(如printf)輸出的字符也不可能在終端上顯示出來。所以,文件描述符為0、1和2 的3個文件(常說的輸入、輸出和報錯)已經(jīng)失去了存在的價值,也應被關(guān)閉。

(7)守護進程退出處理

當用戶需要外部停止守護進程運行時,往往會使用 kill 命令停止該守護進程。所以,守護進程中需要編碼來實現(xiàn) kill 發(fā)出的signal信號處理,達到進程的正常退出。

20.? (Java內(nèi)容)什么是序列化, IO的序列化方式, 為什么需要序列化(包括在網(wǎng)絡傳輸?shù)那闆r下

? ? ? ? 簡單來說序列化就是一種用來處理對象流的機制。所謂對象流也就是將對象的

內(nèi)容進行流化,流的概念這里不用多說(就是I/O)。我們可以對流化后的對象進行讀寫

操作,也可將流化后的對象傳輸于網(wǎng)絡之間(注:要想將對象傳輸于網(wǎng)絡必須進行流化)!

在對對象流進行讀寫操作時會引發(fā)一些問題,而序列化機制正是用來解決這些問題的!

21. 單核CPU執(zhí)行多線程的實現(xiàn)機制

1、鎖--------在單核上,多個線程執(zhí)行鎖或者臨界區(qū)時,實際上只有一個線程在執(zhí)行臨界區(qū)代碼,而核心也只支持一個線程執(zhí)行,因此不存在沖突。如果某個線程持有鎖,那其他線程不會被調(diào)度到CPU上執(zhí)行,影響的只是持有和釋放鎖的時間,處理器時刻在運行著。但是在多核上運行時,鎖或臨界區(qū)會導致其余處理器空閑而只允許一個處理器執(zhí)行持有鎖的那個線程,這是一個串行的過程,會影響性能。

2、負載均衡--------單核上不用考慮負載均衡,因為各個線程輪流執(zhí)行,當一個線程執(zhí)行完時,則會執(zhí)行另外一個線程,不存在線程等待問題。即使各個線程的任務非常不均衡,也不會影響總執(zhí)行時間。而在多核上執(zhí)行時,此時最終時間由運行時間最長的線程決定;

3、任務調(diào)度-------單核上,任務調(diào)度完全是操作系統(tǒng)的工作,無需軟件開發(fā)人員干預,通常有時間片輪轉(zhuǎn)、優(yōu)先級算法等。而在多核上運行時,軟件開發(fā)人員要合理地在核心間分配任務,以盡量同時結(jié)束計算(操作系統(tǒng)轉(zhuǎn)向軟件開發(fā)人員)

4、程序終止--------多線程環(huán)境下,程序終止時需要確定各個線程都已經(jīng)計算完成。

22.? Nginx介紹

什么是Nginx-----------Nginx是一個http服務器。是一個使用c語言開發(fā)的高性能的http服務器及反向代理服務器。Nginx是一款高性能的http 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器。由俄羅斯的程序設(shè)計師Igor Sysoev所開發(fā),官方測試nginx能夠支支撐5萬并發(fā)鏈接,并且cpu、內(nèi)存等資源消耗卻非常低,運行非常穩(wěn)定。

Nginx之(一)Nginx是什么 - CSDN博客

Nginx內(nèi)置的負載均衡策略有3種輪詢加權(quán)輪詢,IP hash? 。同時支持擴展策略,完全可以自己寫一套規(guī)則交給Nginx去執(zhí)行。

23.怎么查看是否出現(xiàn)了內(nèi)存泄漏

c++內(nèi)存泄露檢測 - CSDN博客

用Windows的任務管理器(Task Manager)。運行程序,然后在任務管理器里面查看 “內(nèi)存使用”和”虛擬內(nèi)存大小”兩項,當程序請求了它所需要的內(nèi)存之后,如果虛擬內(nèi)存還是持續(xù)的增長的話,就說明了這個程序有內(nèi)存泄漏問題。

24.多線程的程序如果出現(xiàn)了死鎖怎么去調(diào)試

多線程死鎖調(diào)試小技巧 - KingsLanding - 博客園

25.?實現(xiàn)線程安全的方式有哪些?并介紹一下實現(xiàn)??

基本思路:

(1)給共享的資源加把鎖,保證每個資源變量每時每刻至多被一個線程占用。

(2)讓線程也擁有自己的資源,不用去共享進程中的資源。

具體實現(xiàn):

(1). 多實例、或者是多副本(ThreadLocal):可以為每個線程的維護一個私有的本地變量;

(2). 使用鎖機制 synchronize、lock方式:為資源加鎖

(3). 使用 java.util.concurrent 下面的類庫:有JDK提供的線程安全的集合類


26.?了解線程池不?線程池的基本參數(shù)有哪些?

線程池----------------把一堆開辟好的線程放在一個池子里統(tǒng)一管理,就是一個線程池。線程池是一種多線程處理形式,處理過程中將任務提交到線程池,任務的執(zhí)行交由線程池來管理。

27.?線程池是解決什么問題的?

如果每個請求都創(chuàng)建一個線程去處理,那么服務器的資源很快就會被耗盡,使用線程池可以減少創(chuàng)建和銷毀線程的次數(shù),每個工作線程都可以被重復利用,可執(zhí)行多個任務。

28. 讀寫鎖特性

29.?系統(tǒng)調(diào)用或者說中斷的過程? ( 軟中斷, 硬中斷 )?

30.自旋鎖 ??自旋鎖與互斥鎖的對比、手工實現(xiàn)自旋鎖 - CSDN博客

采用讓當前線程不停的在循環(huán)體內(nèi)執(zhí)行實現(xiàn),當循環(huán)的條件被其它線程改變時才能進入臨界區(qū)

優(yōu)點:由于自旋鎖只是將當前線程不停地執(zhí)行循環(huán)體,不進行線程狀態(tài)的改變,所以響應速度更快。

缺點:但當線程數(shù)不停增加時,性能下降明顯,因為每個線程都需要執(zhí)行,占用CPU時間。如果線程競爭不激烈,并且保持鎖的時間段。適合使用自旋鎖。

自旋鎖是一種用于保護多線程共享資源的鎖,與一般互斥鎖(mutex)不同之處在于當自旋鎖嘗試獲取鎖時以忙等待(busy waiting)的形式不斷地循環(huán)檢查鎖是否可用。在多CPU的環(huán)境中,對持有鎖較短的程序來說,使用自旋鎖代替一般的互斥鎖往往能夠提高程序的性能。

31. CPU是怎么執(zhí)行指令的

cpu執(zhí)行指令的過程詳解

  計算機每執(zhí)行一條指令都可分為三個階段進行。即 ??

? ? ? ? 取指令-----分析指令-----執(zhí)行指令

  (1)取指令:根據(jù)程序計數(shù)器PC中的值從程序存儲器讀出現(xiàn)行指令,送到指令寄存器。

  (2)分析指令:將指令寄存器中的指令操作碼取出后進行譯碼,分析其指令性質(zhì)。如指令要求操作數(shù),則尋找操作數(shù)地址。

 ?。?)執(zhí)行指令:計算機執(zhí)行程序的過程實際上就是逐條指令地重復上述操作過程,直至遇到停機指令可循環(huán)等待指令。

32. 互斥量(鎖),臨界區(qū),事件,信號量的區(qū)別

(1)互斥量與臨界區(qū)的作用非常相似,但互斥量是可以命名的,也就是說它可以跨越進程使用。所以創(chuàng)建互斥量需要的資源更多,所以如果只為了在進程內(nèi)部使用的話使用臨界區(qū)會帶來速度上的優(yōu)勢并能夠減少資源占用量。因為互斥量是跨進程的互斥量一旦被創(chuàng)建,就可以通過名字打開它。 (鎖或者說互斥量可以不僅可以在統(tǒng)一進程的不同線程中使用,還可以跨進程對不同進程使用,而臨界區(qū)只能在進程內(nèi)部針對不同線程使用)

(2)互斥量(Mutex),信號燈(Semaphore),事件(Event)都可以被跨越進程使用來進行同步數(shù)據(jù)操作,而其他的對象與數(shù)據(jù)同步操作無關(guān),但對于進程和線程來講,如果進程和線程在運行狀態(tài)則為無信號狀態(tài),在退出后為有信號狀態(tài)。所以可以使用WaitForSingleObject來等待進程和線程退出。

(3)通過互斥量可以指定資源被獨占的方式使用,但如果有下面一種情況通過互斥量就無法處理,比如現(xiàn)在一位用戶購買了一份三個并發(fā)訪問許可的數(shù)據(jù)庫系統(tǒng),可以根據(jù)用戶購買的訪問許可數(shù)量來決定有多少個線程/進程能同時進行數(shù)據(jù)庫操作,這時候如果利用互斥量就沒有辦法完成這個要求,信號燈對象可以說是一種資源計數(shù)器。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容