聊一聊操作系統(tǒng)八股文背誦版
備受期待的操作系統(tǒng)八股文來(lái)啦!
八股文在線網(wǎng)址: http://interviewtop.top
求大家給我們的八股文項(xiàng)目github來(lái)個(gè)贊!https://github.com/autoencoder-github/interviewtop
什么是操作系統(tǒng)?請(qǐng)簡(jiǎn)要概述一下
操作系統(tǒng)是管理計(jì)算機(jī)硬件和軟件資源的計(jì)算機(jī)程序,提供一個(gè)計(jì)算機(jī)用戶與計(jì)算機(jī)硬件系統(tǒng)之間的接口。
向上對(duì)用戶程序提供接口,向下接管硬件資源。
操作系統(tǒng)本質(zhì)上也是一個(gè)軟件,作為最接近硬件的系統(tǒng)軟件,負(fù)責(zé)處理器管理、存儲(chǔ)器管理、設(shè)備管理、文件管理和提供用戶接口。
操作系統(tǒng)有哪些分類?
操作系統(tǒng)常規(guī)可分為批處理操作系統(tǒng)、分時(shí)操作系統(tǒng)、實(shí)時(shí)操作系統(tǒng)。
若一個(gè)操作系統(tǒng)兼顧批操作和分時(shí)的功能,則稱該系統(tǒng)為通用操作系統(tǒng)。
常見(jiàn)的通用操作系統(tǒng)有:Windows、Linux、MacOS等。
什么是內(nèi)核態(tài)和用戶態(tài)?
為了避免操作系統(tǒng)和關(guān)鍵數(shù)據(jù)被用戶程序破壞,將處理器的執(zhí)行狀態(tài)分為內(nèi)核態(tài)和用戶態(tài)。
內(nèi)核態(tài)是操作系統(tǒng)管理程序執(zhí)行時(shí)所處的狀態(tài),能夠執(zhí)行包含特權(quán)指令在內(nèi)的一切指令,能夠訪問(wèn)系統(tǒng)內(nèi)所有的存儲(chǔ)空間。
用戶態(tài)是用戶程序執(zhí)行時(shí)處理器所處的狀態(tài),不能執(zhí)行特權(quán)指令,只能訪問(wèn)用戶地址空間。
用戶程序運(yùn)行在用戶態(tài),操作系統(tǒng)內(nèi)核運(yùn)行在內(nèi)核態(tài)。
如何實(shí)現(xiàn)內(nèi)核態(tài)和用戶態(tài)的切換?
處理器從用戶態(tài)切換到內(nèi)核態(tài)的方法有三種:系統(tǒng)調(diào)用、異常和外部中斷。
- 系統(tǒng)調(diào)用是操作系統(tǒng)的最小功能單位,是操作系統(tǒng)提供的用戶接口,系統(tǒng)調(diào)用本身是一種軟中斷。
- 異常,也叫做內(nèi)中斷,是由錯(cuò)誤引起的,如文件損壞、缺頁(yè)故障等。
- 外部中斷,是通過(guò)兩根信號(hào)線來(lái)通知處理器外設(shè)的狀態(tài)變化,是硬中斷。
并發(fā)和并行的區(qū)別
- 并發(fā)(concurrency):指宏觀上看起來(lái)兩個(gè)程序在同時(shí)運(yùn)行,比如說(shuō)在單核cpu上的多任務(wù)。但是從微觀上看兩個(gè)程序的指令是交織著運(yùn)行的,指令之間交錯(cuò)執(zhí)行,在單個(gè)周期內(nèi)只運(yùn)行了一個(gè)指令。這種并發(fā)并不能提高計(jì)算機(jī)的性能,只能提高效率(如降低某個(gè)進(jìn)程的相應(yīng)時(shí)間)。
- 并行(parallelism):指嚴(yán)格物理意義上的同時(shí)運(yùn)行,比如多核cpu,兩個(gè)程序分別運(yùn)行在兩個(gè)核上,兩者之間互不影響,單個(gè)周期內(nèi)每個(gè)程序都運(yùn)行了自己的指令,也就是運(yùn)行了兩條指令。這樣說(shuō)來(lái)并行的確提高了計(jì)算機(jī)的效率。所以現(xiàn)在的cpu都是往多核方面發(fā)展。
什么是進(jìn)程?
進(jìn)程是操作系統(tǒng)中最重要的抽象概念之一,是資源分配的基本單位,是獨(dú)立運(yùn)行的基本單位。
進(jìn)程的經(jīng)典定義就是一個(gè)執(zhí)行中程序的實(shí)例。系統(tǒng)中的每個(gè)程序都運(yùn)行在某個(gè)進(jìn)程的上下文(context)中。
上下文是由程序正確運(yùn)行所需的狀態(tài)組成的。這個(gè)狀態(tài)包括存放在內(nèi)存中的程序的代碼和數(shù)據(jù),它的棧、通用目的寄存器的內(nèi)容、程序計(jì)數(shù)器、環(huán)境變量以及打開(kāi)文件描述符的集合。
進(jìn)程一般由以下的部分組成:
- 進(jìn)程控制塊PCB,是進(jìn)程存在的唯一標(biāo)志,包含進(jìn)程標(biāo)識(shí)符PID,進(jìn)程當(dāng)前狀態(tài),程序和數(shù)據(jù)地址,進(jìn)程優(yōu)先級(jí)、CPU現(xiàn)場(chǎng)保護(hù)區(qū)(用于進(jìn)程切換),占有的資源清單等。
- 程序段
- 數(shù)據(jù)段
進(jìn)程的基本操作
以Unix系統(tǒng)舉例:
進(jìn)程的創(chuàng)建:fork()。新創(chuàng)建的子進(jìn)程幾乎但不完全與父進(jìn)程相同。子進(jìn)程得到與父進(jìn)程用戶級(jí)虛擬地址空間相同的(但是獨(dú)立的)一份副本,包括代碼和數(shù)據(jù)段、堆、共享庫(kù)以及用戶棧。子進(jìn)程還獲得與父進(jìn)程任何打開(kāi)文件描述符相同的副本,這就意味著當(dāng)父進(jìn)程調(diào)用 fork 時(shí),子進(jìn)程可以讀寫父進(jìn)程中打開(kāi)的任何文件。父進(jìn)程和新創(chuàng)建的子進(jìn)程之間最大的區(qū)別在于它們有不同的 PID。fork函數(shù)是有趣的(也常常令人迷惑), 因?yàn)樗槐徽{(diào)用一次,卻會(huì)返回兩次:一次是在調(diào)用進(jìn)程(父進(jìn)程)中,一次是在新創(chuàng)建的子進(jìn)程中。在父進(jìn)程中,fork 返回子進(jìn)程的 PID。在子進(jìn)程中,fork 返回 0。因?yàn)樽舆M(jìn)程的 PID 總是為非零,返回值就提供一個(gè)明 確的方法來(lái)分辨程序是在父進(jìn)程還是在子進(jìn)程中執(zhí)行。
- pid_t fork(void);
回收子進(jìn)程:當(dāng)一個(gè)進(jìn)程由于某種原因終止時(shí),內(nèi)核并不是立即把它從系統(tǒng)中清除。相反,進(jìn)程被保持在一種已終止的狀態(tài)中,直到被它的父進(jìn)程回收(reaped)。當(dāng)父進(jìn)程回收已終止的子進(jìn)程時(shí),內(nèi)核將子進(jìn)程的退出狀態(tài)傳遞給父進(jìn)程,然后拋棄已終止的進(jìn)程。一個(gè)進(jìn)程可以通過(guò)調(diào)用 waitpid 函數(shù)來(lái)等待它的子進(jìn)程終止或者停止。
- pid_t waitpid(pid_t pid, int *statusp, int options);
加載并運(yùn)行程序:execve 函數(shù)在當(dāng)前進(jìn)程的上下文中加載并運(yùn)行一個(gè)新程序。
- int execve(const char *filename, const char *argv[], const char *envp[]);
進(jìn)程終止:
- void exit(int status);
簡(jiǎn)述進(jìn)程間通信方法
每個(gè)進(jìn)程各自有不同的用戶地址空間,任何一個(gè)進(jìn)程的全局變量在另一個(gè)進(jìn)程中都看不到,所以進(jìn)程之間要交換數(shù)據(jù)必須通過(guò)內(nèi)核,在內(nèi)核中開(kāi)辟一塊緩沖區(qū),進(jìn)程A把數(shù)據(jù)從用戶空間拷到內(nèi)核緩沖區(qū),進(jìn)程B再?gòu)膬?nèi)核緩沖區(qū)把數(shù)據(jù)讀走,內(nèi)核提供的這種機(jī)制稱為進(jìn)程間通信。
不同進(jìn)程間的通信本質(zhì):進(jìn)程之間可以看到一份公共資源;而提供這份資源的形式或者提供者不同,造成了通信方式不同。
進(jìn)程間通信主要包括管道、系統(tǒng)IPC(包括消息隊(duì)列、信號(hào)量、信號(hào)、共享內(nèi)存等)、以及套接字socket。
進(jìn)程如何通過(guò)管道進(jìn)行通信
管道是一種最基本的IPC機(jī)制,作用于有血緣關(guān)系的進(jìn)程之間,完成數(shù)據(jù)傳遞。調(diào)用pipe系統(tǒng)函數(shù)即可創(chuàng)建一個(gè)管道。有如下特質(zhì):
- 其本質(zhì)是一個(gè)偽文件(實(shí)為內(nèi)核緩沖區(qū))
- 由兩個(gè)文件描述符引用,一個(gè)表示讀端,一個(gè)表示寫端。
- 規(guī)定數(shù)據(jù)從管道的寫端流入管道,從讀端流出。
管道的原理: 管道實(shí)為內(nèi)核使用環(huán)形隊(duì)列機(jī)制,借助內(nèi)核緩沖區(qū)實(shí)現(xiàn)。
管道的局限性:
- 數(shù)據(jù)自己讀不能自己寫。
- 數(shù)據(jù)一旦被讀走,便不在管道中存在,不可反復(fù)讀取。
- 由于管道采用半雙工通信方式。因此,數(shù)據(jù)只能在一個(gè)方向上流動(dòng)。
- 只能在有公共祖先的進(jìn)程間使用管道。
進(jìn)程如何通過(guò)共享內(nèi)存通信?
它使得多個(gè)進(jìn)程可以訪問(wèn)同一塊內(nèi)存空間,不同進(jìn)程可以及時(shí)看到對(duì)方進(jìn)程中對(duì)共享內(nèi)存中數(shù)據(jù)得更新。這種方式需要依靠某種同步操作,如互斥鎖和信號(hào)量等。
特點(diǎn):
- 共享內(nèi)存是最快的一種IPC,因?yàn)檫M(jìn)程是直接對(duì)內(nèi)存進(jìn)行操作來(lái)實(shí)現(xiàn)通信,避免了數(shù)據(jù)在用戶空間和內(nèi)核空間來(lái)回拷貝。
- 因?yàn)槎鄠€(gè)進(jìn)程可以同時(shí)操作,所以需要進(jìn)行同步處理。
- 信號(hào)量和共享內(nèi)存通常結(jié)合在一起使用,信號(hào)量用來(lái)同步對(duì)共享內(nèi)存的訪問(wèn)。
什么是信號(hào)
一個(gè)信號(hào)就是一條小消息,它通知進(jìn)程系統(tǒng)中發(fā)生了一個(gè)某種類型的事件。Linux 系統(tǒng)上支持的30 種不同類型的信號(hào)。每種信號(hào)類型都對(duì)應(yīng)于某種系統(tǒng)事件。低層的硬件異常是由內(nèi)核異常處理程序處理的,正常情況下,對(duì)用戶進(jìn)程而言是不可見(jiàn)的。信號(hào)提供了一種機(jī)制,通知用戶進(jìn)程發(fā)生了這些異常。
發(fā)送信號(hào):內(nèi)核通過(guò)更新目的進(jìn)程上下文中的某個(gè)狀態(tài),發(fā)送(遞送)一個(gè)信號(hào)給目的進(jìn)程。發(fā)送信號(hào)可以有如下兩種原因:
- 內(nèi)核檢測(cè)到一個(gè)系統(tǒng)事件,比如除零錯(cuò)誤或者子進(jìn)程終止。
- —個(gè)進(jìn)程調(diào)用了kill 函數(shù), 顯式地要求內(nèi)核發(fā)送一個(gè)信號(hào)給目的進(jìn)程。一個(gè)進(jìn)程可以發(fā)送信號(hào)給它自己。
接收信號(hào):當(dāng)目的進(jìn)程被內(nèi)核強(qiáng)迫以某種方式對(duì)信號(hào)的發(fā)送做出反應(yīng)時(shí),它就接收了信號(hào)。進(jìn)程可以忽略這個(gè)信號(hào),終止或者通過(guò)執(zhí)行一個(gè)稱為信號(hào)處理程序(signal handler)的用戶層函數(shù)捕獲這個(gè)信號(hào)。
如何編寫正確且安全的信號(hào)處理函數(shù)
1.處理程序要盡可能簡(jiǎn)單。避免麻煩的最好方法是保持處理程序盡可能小和簡(jiǎn)單。例如,處理程序可能只是簡(jiǎn)單地設(shè)置全局標(biāo)志并立即返回;所有與接收信號(hào)相關(guān)的處理都由主程序執(zhí)行,它周期性地檢查(并重置)這個(gè)標(biāo)志。
2.在處理程序中只調(diào)用異步信號(hào)安全的函數(shù)。所謂異步信號(hào)安全的函數(shù)(或簡(jiǎn)稱安全的函數(shù))能夠被信號(hào)處理程序安全地調(diào)用,原因有二:要么它是可重入的(例如只訪問(wèn)局部變量),要么它不能被信號(hào)處理程序中斷。
3.保存和恢復(fù)errno。許多Linux 異步信號(hào)安全的函數(shù)都會(huì)在出錯(cuò)返回時(shí)設(shè)置errno在處理程序中調(diào)用這樣的函數(shù)可能會(huì)干擾主程序中其他依賴于分。解決方法是在進(jìn)人處理程序時(shí)把errno 保存在一個(gè)局部變量中,在處理程序返回前恢復(fù)它。注意,只有在處理程序要返回時(shí)才有此必要。如果處理程序調(diào)用_exit終止該進(jìn)程,那么就不需要這樣做了。
4.阻塞所有的信號(hào),保護(hù)對(duì)共享全局?jǐn)?shù)據(jù)結(jié)構(gòu)的訪問(wèn)。如果處理程序和主程序或其他處理程序共享一個(gè)全局?jǐn)?shù)據(jù)結(jié)構(gòu),那么在訪問(wèn)(讀或者寫)該數(shù)據(jù)結(jié)構(gòu)時(shí),你的處理程序和主程序應(yīng)該暫時(shí)阻塞所有的信號(hào)。這條規(guī)則的原因是從主程序訪問(wèn)一個(gè)數(shù)據(jù)結(jié)構(gòu)d 通常需要一系列的指令,如果指令序列被訪問(wèn)d 的處理程序中斷,那么處理程序可能會(huì)發(fā)現(xiàn)d 的狀態(tài)不一致,得到不可預(yù)知的結(jié)果。在訪問(wèn)d 時(shí)暫時(shí)阻塞信號(hào)保證了處理程序不會(huì)中斷該指令序列。
5.用volatile 聲明全局變量??紤]一個(gè)處理程序和一個(gè)main 函數(shù),它們共享一個(gè)全局變量g 。處理程序更新g,main 周期性地讀g, 對(duì)于一個(gè)優(yōu)化編譯器而言,main 中g(shù)的值看上去從來(lái)沒(méi)有變化過(guò),因此使用緩存在寄存器中g(shù) 的副本來(lái)滿足對(duì)g 的每次引用是很安全的。如果這樣,main 函數(shù)可能永遠(yuǎn)都無(wú)法看到處理程序更新過(guò)的值??梢杂胿olatile 類型限定符來(lái)定義一個(gè)變量,告訴編譯器不要緩存這個(gè)變量。例如:volatile 限定符強(qiáng)迫編譯器毎次在代碼中引用g時(shí),都要從內(nèi)存中讀取g的值。一般來(lái)說(shuō),和其他所有共享數(shù)據(jù)結(jié)構(gòu)一樣,應(yīng)該暫時(shí)阻塞信號(hào),保護(hù)每次對(duì)全局變量的訪問(wèn)。
- volatile int g;
6.用sig_atomic_t聲明標(biāo)志。在常見(jiàn)的處理程序設(shè)計(jì)中,處理程序會(huì)寫全局標(biāo)志來(lái)記錄收到了信號(hào)。主程序周期性地讀這個(gè)標(biāo)志,響應(yīng)信號(hào),再清除該標(biāo)志。對(duì)于通過(guò)這種方式來(lái)共享的標(biāo)志,C 提供一種整型數(shù)據(jù)類型sig_atomic_t對(duì)它的讀和寫保證會(huì)是原子的(不可中斷的)。
7.信號(hào)的一個(gè)與直覺(jué)不符的方面是未處理的信號(hào)是不排隊(duì)的。因?yàn)?pending 位向量中每種類型的信號(hào)只對(duì)應(yīng)有一位,所以每種類型最多只能有一個(gè)未處理的信號(hào)。關(guān)鍵思想是如果存在一個(gè)未處理的信號(hào)就表明至少有一個(gè)信號(hào)到達(dá)了。
進(jìn)程調(diào)度的時(shí)機(jī)
- 當(dāng)前運(yùn)行的進(jìn)程運(yùn)行結(jié)束。
- 當(dāng)前運(yùn)行的進(jìn)程由于某種原因阻塞。
- 執(zhí)行完系統(tǒng)調(diào)用等系統(tǒng)程序后返回用戶進(jìn)程。
- 在使用搶占調(diào)度的系統(tǒng)中,具有更高優(yōu)先級(jí)的進(jìn)程就緒時(shí)。
- 分時(shí)系統(tǒng)中,分給當(dāng)前進(jìn)程的時(shí)間片用完。
不能進(jìn)行進(jìn)程調(diào)度的情況
- 在中斷處理程序執(zhí)行時(shí)。
- 在操作系統(tǒng)的內(nèi)核程序臨界區(qū)內(nèi)。
- 其它需要完全屏蔽中斷的原子操作過(guò)程中。
進(jìn)程的調(diào)度策略
- 先到先服務(wù)調(diào)度算法
- 短作業(yè)優(yōu)先調(diào)度算法
- 優(yōu)先級(jí)調(diào)度算法
- 時(shí)間片輪轉(zhuǎn)調(diào)度算法
- 高響應(yīng)比優(yōu)先調(diào)度算法
- 多級(jí)隊(duì)列調(diào)度算法
- 多級(jí)反饋隊(duì)列調(diào)度算法
進(jìn)程調(diào)度策略的基本設(shè)計(jì)指標(biāo)
- CPU利用率
- 系統(tǒng)吞吐率,即單位時(shí)間內(nèi)CPU完成的作業(yè)的數(shù)量。
- 響應(yīng)時(shí)間。
- 周轉(zhuǎn)時(shí)間。是指作業(yè)從提交到完成的時(shí)間間隔。從每個(gè)作業(yè)的角度看,完成每個(gè)作業(yè)的時(shí)間也是很關(guān)鍵
- 平均周轉(zhuǎn)時(shí)間
- 帶權(quán)周轉(zhuǎn)時(shí)間
- 平均帶權(quán)周轉(zhuǎn)時(shí)間
進(jìn)程的狀態(tài)與狀態(tài)轉(zhuǎn)換
進(jìn)程在運(yùn)行時(shí)有三種基本狀態(tài):就緒態(tài)、運(yùn)行態(tài)和阻塞態(tài)。
1.運(yùn)行(running)態(tài):進(jìn)程占有處理器正在運(yùn)行的狀態(tài)。進(jìn)程已獲得CPU,其程序正在執(zhí)行。在單處理機(jī)系統(tǒng)中,只有一個(gè)進(jìn)程處于執(zhí)行狀態(tài);在多處理機(jī)系統(tǒng)中,則有多個(gè)進(jìn)程處于執(zhí)行狀態(tài)。
2.就緒(ready)態(tài):進(jìn)程具備運(yùn)行條件,等待系統(tǒng)分配處理器以便運(yùn)行的狀態(tài)。 當(dāng)進(jìn)程已分配到除CPU以外的所有必要資源后,只要再獲得CPU,便可立即執(zhí)行,進(jìn)程這時(shí)的狀態(tài)稱為就緒狀態(tài)。在一個(gè)系統(tǒng)中處于就緒狀態(tài)的進(jìn)程可能有多個(gè),通常將它們排成一個(gè)隊(duì)列,稱為就緒隊(duì)列。
3.阻塞(wait)態(tài):又稱等待態(tài)或睡眠態(tài),指進(jìn)程不具備運(yùn)行條件,正在等待某個(gè)時(shí)間完成的狀態(tài)。
各狀態(tài)之間的轉(zhuǎn)換:
就緒→執(zhí)行 處于就緒狀態(tài)的進(jìn)程,當(dāng)進(jìn)程調(diào)度程序?yàn)橹峙淞颂幚頇C(jī)后,該進(jìn)程便由就緒狀態(tài)轉(zhuǎn)變成執(zhí)行狀態(tài)。
執(zhí)行→就緒 處于執(zhí)行狀態(tài)的進(jìn)程在其執(zhí)行過(guò)程中,因分配給它的一個(gè)時(shí)間片已用完而不得不讓出處理機(jī),于是進(jìn)程從執(zhí)行狀態(tài)轉(zhuǎn)變成就緒狀態(tài)。
執(zhí)行→阻塞 正在執(zhí)行的進(jìn)程因等待某種事件發(fā)生而無(wú)法繼續(xù)執(zhí)行時(shí),便從執(zhí)行狀態(tài)變成阻塞狀態(tài)。
阻塞→就緒 處于阻塞狀態(tài)的進(jìn)程,若其等待的事件已經(jīng)發(fā)生,于是進(jìn)程由阻塞狀態(tài)轉(zhuǎn)變?yōu)榫途w狀態(tài)。
什么是孤兒進(jìn)程?僵尸進(jìn)程?
1.孤兒進(jìn)程:父進(jìn)程退出,子進(jìn)程還在運(yùn)行的這些子進(jìn)程都是孤兒進(jìn)程,孤兒進(jìn)程將被init進(jìn)程(1號(hào)進(jìn)程)所收養(yǎng),并由init進(jìn)程對(duì)他們完成狀態(tài)收集工作。
2.僵尸進(jìn)程:進(jìn)程使用fork創(chuàng)建子進(jìn)程,如果子進(jìn)程退出,而父進(jìn)程并沒(méi)有調(diào)用wait 獲waitpid 獲取子進(jìn)程的狀態(tài)信息,那么子進(jìn)程的進(jìn)程描述符仍然保存在系統(tǒng)中的這些進(jìn)程是僵尸進(jìn)程。
什么是線程?
- 是進(jìn)程劃分的任務(wù),是一個(gè)進(jìn)程內(nèi)可調(diào)度的實(shí)體,是CPU調(diào)度的基本單位,用于保證程序的實(shí)時(shí)性,實(shí)現(xiàn)進(jìn)程內(nèi)部的并發(fā)。
- 線程是操作系統(tǒng)可識(shí)別的最小執(zhí)行和調(diào)度單位。每個(gè)線程都獨(dú)自占用一個(gè)虛擬處理器:獨(dú)自的寄存器組,指令計(jì)數(shù)器和處理器狀態(tài)。
- 每個(gè)線程完成不同的任務(wù),但是屬于同一個(gè)進(jìn)程的不同線程之間共享同一地址空間(也就是同樣的動(dòng)態(tài)內(nèi)存,映射文件,目標(biāo)代碼等等),打開(kāi)的文件隊(duì)列和其他內(nèi)核資源。
為什么需要線程?
線程產(chǎn)生的原因:進(jìn)程可以使多個(gè)程序能并發(fā)執(zhí)行,以提高資源的利用率和系統(tǒng)的吞吐量;但是其具有一些缺點(diǎn):
- 進(jìn)程在同一時(shí)刻只能做一個(gè)任務(wù),很多時(shí)候不能充分利用CPU資源。
- 進(jìn)程在執(zhí)行的過(guò)程中如果發(fā)生阻塞,整個(gè)進(jìn)程就會(huì)掛起,即使進(jìn)程中其它任務(wù)不依賴于等待的資源,進(jìn)程仍會(huì)被阻塞。
引入線程就是為了解決以上進(jìn)程的不足,線程具有以下的優(yōu)點(diǎn):
- 從資源上來(lái)講,開(kāi)辟一個(gè)線程所需要的資源要遠(yuǎn)小于一個(gè)進(jìn)程。
- 從切換效率上來(lái)講,運(yùn)行于一個(gè)進(jìn)程中的多個(gè)線程,它們之間使用相同的地址空間,而且線程間彼此切換所需時(shí)間也遠(yuǎn)遠(yuǎn)小于進(jìn)程間切換所需要的時(shí)間(這種時(shí)間的差異主要由于緩存的大量未命中導(dǎo)致)。
- 從通信機(jī)制上來(lái)講,線程間方便的通信機(jī)制。對(duì)不同進(jìn)程來(lái)說(shuō),它們具有獨(dú)立的地址空間,要進(jìn)行數(shù)據(jù)的傳遞只能通過(guò)進(jìn)程間通信的方式進(jìn)行。線程則不然,屬于同一個(gè)進(jìn)程的不同線程之間共享同一地址空間,所以一個(gè)線程的數(shù)據(jù)可以被其它線程感知,線程間可以直接讀寫進(jìn)程數(shù)據(jù)段(如全局變量)來(lái)進(jìn)行通信(需要一些同步措施)。
簡(jiǎn)述線程和進(jìn)程的區(qū)別和聯(lián)系
- 一個(gè)線程只能屬于一個(gè)進(jìn)程,而一個(gè)進(jìn)程可以有多個(gè)線程,但至少有一個(gè)線程。線程依賴于進(jìn)程而存在。
- 進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的地址空間,而多個(gè)線程共享進(jìn)程的地址空間。(資源分配給進(jìn)程,同一進(jìn)程的所有線程共享該進(jìn)程的所有資源。同一進(jìn)程中的多個(gè)線程共享代碼段(代碼和常量),數(shù)據(jù)段(全局變量和靜態(tài)變量),擴(kuò)展段(堆存儲(chǔ))。但是每個(gè)線程擁有自己的棧段,棧段又叫運(yùn)行時(shí)段,用來(lái)存放所有局部變量和臨時(shí)變量。)
- 進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位。
- 通信:由于同一進(jìn)程中的多個(gè)線程具有相同的地址空間,使它們之間的同步和通信的實(shí)現(xiàn),也變得比較容易。進(jìn)程間通信IPC,線程間可以直接讀寫進(jìn)程數(shù)據(jù)段(如全局變量)來(lái)進(jìn)行通信(需要一些同步方法,以保證數(shù)據(jù)的一致性)。
- 進(jìn)程編程調(diào)試簡(jiǎn)單可靠性高,但是創(chuàng)建銷毀開(kāi)銷大;線程正相反,開(kāi)銷小,切換速度快,但是編程調(diào)試相對(duì)復(fù)雜。
- 進(jìn)程間不會(huì)相互影響;一個(gè)進(jìn)程內(nèi)某個(gè)線程掛掉將導(dǎo)致整個(gè)進(jìn)程掛掉。
- 進(jìn)程適應(yīng)于多核、多機(jī)分布;線程適用于多核。
進(jìn)程和線程的基本API
進(jìn)程API以Unix系統(tǒng)為例,線程相關(guān)的API屬于Posix線程(Pthreads)標(biāo)準(zhǔn)接口。
進(jìn)程原語(yǔ) | 線程原語(yǔ) | 描述 |
---|---|---|
fork |
pthread_create |
創(chuàng)建新的控制流 |
exit |
pthread_exit |
從現(xiàn)有的控制流中退出 |
waitpid |
pthread_join |
從控制流中得到退出狀態(tài) |
atexit |
pthread_cancel_push |
注冊(cè)在退出控制流時(shí)調(diào)用的函數(shù) |
getpid |
pthread_self |
獲取控制流的ID |
abort |
pthread_cancel |
請(qǐng)求控制流的非正常退出 |
多線程模型
- 多對(duì)一模型。將多個(gè)用戶級(jí)線程映射到一個(gè)內(nèi)核級(jí)線程上。該模型下,線程在用戶空間進(jìn)行管理,效率較高。缺點(diǎn)就是一個(gè)線程阻塞,整個(gè)進(jìn)程內(nèi)的所有線程都會(huì)阻塞。幾乎沒(méi)有系統(tǒng)繼續(xù)使用這個(gè)模型。
- 一對(duì)一模型。將內(nèi)核線程與用戶線程一一對(duì)應(yīng)。優(yōu)點(diǎn)是一個(gè)線程阻塞時(shí),不會(huì)影響到其它線程的執(zhí)行。該模型具有更好的并發(fā)性。缺點(diǎn)是內(nèi)核線程數(shù)量一般有上限,會(huì)限制用戶線程的數(shù)量。更多的內(nèi)核線程數(shù)目也給線程切換帶來(lái)額外的負(fù)擔(dān)。linux和Windows操作系統(tǒng)家族都是使用一對(duì)一模型。
- 多對(duì)多模型。將多個(gè)用戶級(jí)線程映射到多個(gè)內(nèi)核級(jí)線程上。結(jié)合了多對(duì)一模型和一對(duì)一模型的特點(diǎn)。
進(jìn)程同步的方法
操作系統(tǒng)中,進(jìn)程是具有不同的地址空間的,兩個(gè)進(jìn)程是不能感知到對(duì)方的存在的。有時(shí)候,需要多個(gè)進(jìn)程來(lái)協(xié)同完成一些任務(wù)。當(dāng)多個(gè)進(jìn)程需要對(duì)同一個(gè)內(nèi)核資源進(jìn)行操作時(shí),這些進(jìn)程便是競(jìng)爭(zhēng)的關(guān)系,操作系統(tǒng)必須協(xié)調(diào)各個(gè)進(jìn)程對(duì)資源的占用,進(jìn)程的互斥是解決進(jìn)程間競(jìng)爭(zhēng)關(guān)系的方法。進(jìn)程互斥指若干個(gè)進(jìn)程要使用同一共享資源時(shí),任何時(shí)刻最多允許一個(gè)進(jìn)程去使用,其他要使用該資源的進(jìn)程必須等待,直到占有資源的進(jìn)程釋放該資源。當(dāng)多個(gè)進(jìn)程協(xié)同完成一些任務(wù)時(shí),不同進(jìn)程的執(zhí)行進(jìn)度不一致,這便產(chǎn)生了進(jìn)程的同步問(wèn)題。需要操作系統(tǒng)干預(yù),在特定的同步點(diǎn)對(duì)所有進(jìn)程進(jìn)行同步,這種協(xié)作進(jìn)程之間相互等待對(duì)方消息或信號(hào)的協(xié)調(diào)關(guān)系稱為進(jìn)程同步。進(jìn)程互斥本質(zhì)上也是一種進(jìn)程同步。進(jìn)程的同步方法:
- 互斥鎖
- 讀寫鎖
- 條件變量
- 記錄鎖(record locking)
- 信號(hào)量
- 屏障(barrier)
線程同步的方法
操作系統(tǒng)中,屬于同一進(jìn)程的線程之間具有相同的地址空間,線程之間共享數(shù)據(jù)變得簡(jiǎn)單高效。遇到競(jìng)爭(zhēng)的線程同時(shí)修改同一數(shù)據(jù)或是協(xié)作的線程設(shè)置同步點(diǎn)的問(wèn)題時(shí),需要使用一些線程同步的方法來(lái)解決這些問(wèn)題。
線程同步的方法:
- 互斥鎖
- 讀寫鎖
- 條件變量
- 信號(hào)量
- 自旋鎖
- 屏障(barrier)
進(jìn)程同步與線程同步有什么區(qū)別
進(jìn)程之間地址空間不同,不能感知對(duì)方的存在,同步時(shí)需要將鎖放在多進(jìn)程共享的空間。而線程之間共享同一地址空間,同步時(shí)把鎖放在所屬的同一進(jìn)程空間即可。
死鎖是怎樣產(chǎn)生的?
死鎖是指兩個(gè)或兩個(gè)以上進(jìn)程在執(zhí)行過(guò)程中,因爭(zhēng)奪資源而造成的下相互等待的現(xiàn)象。產(chǎn)生死鎖需要滿足下面四個(gè)條件:
- 互斥條件:進(jìn)程對(duì)所分配到的資源不允許其他進(jìn)程訪問(wèn),若其他進(jìn)程訪問(wèn)該資源,只能等待,直至占有該資源的進(jìn)程使用完成后釋放該資源。
- 占有并等待條件:進(jìn)程獲得一定的資源后,又對(duì)其他資源發(fā)出請(qǐng)求,但是該資源可能被其他進(jìn)程占有,此時(shí)請(qǐng)求阻塞,但該進(jìn)程不會(huì)釋放自己已經(jīng)占有的資源。
- 非搶占條件:進(jìn)程已獲得的資源,在未完成使用之前,不可被剝奪,只能在使用后自己釋放。
- 循環(huán)等待條件:進(jìn)程發(fā)生死鎖后,必然存在一個(gè)進(jìn)程-資源之間的環(huán)形鏈。
如何解決死鎖問(wèn)題?
解決死鎖的方法即破壞產(chǎn)生死鎖的四個(gè)必要條件之一,主要方法如下:
- 資源一次性分配,這樣就不會(huì)再有請(qǐng)求了(破壞請(qǐng)求條件)。
- 只要有一個(gè)資源得不到分配,也不給這個(gè)進(jìn)程分配其他的資源(破壞占有并等待條件)。
- 可搶占資源:即當(dāng)進(jìn)程新的資源未得到滿足時(shí),釋放已占有的資源,從而破壞不可搶占的條件。
- 資源有序分配法:系統(tǒng)給每類資源賦予一個(gè)序號(hào),每個(gè)進(jìn)程按編號(hào)遞增的請(qǐng)求資源,釋放則相反,從而破壞環(huán)路等待的條件
什么是虛擬地址,什么是物理地址?
地址空間是一個(gè)非負(fù)整數(shù)地址的有序集合。
在一個(gè)帶虛擬內(nèi)存的系統(tǒng)中,CPU 從一個(gè)有N=pow(2,n)個(gè)地址的地址空間中生成虛擬地址,這個(gè)地址空間稱為虛擬地址空間(virtual address space),現(xiàn)代系統(tǒng)通常支持 32 位或者 64 位虛擬地址空間。
一個(gè)系統(tǒng)還有一個(gè)物理地址空間(physical address space),對(duì)應(yīng)于系統(tǒng)中物理內(nèi)存的M 個(gè)字節(jié)。
地址空間的概念是很重要的,因?yàn)樗宄貐^(qū)分了數(shù)據(jù)對(duì)象(字節(jié))和它們的屬性(地址)。
一旦認(rèn)識(shí)到了這種區(qū)別,那么我們就可以將其推廣,允許每個(gè)數(shù)據(jù)對(duì)象有多個(gè)獨(dú)立的地址,其中每個(gè)地址都選自一個(gè)不同的地址空間。這就是虛擬內(nèi)存的基本思想。
主存中的每字節(jié)都有一個(gè)選自虛擬地址空間的虛擬地址和一個(gè)選自物理地址空間的物理地址。
什么是虛擬內(nèi)存?
為了更加有效地管理內(nèi)存并且少出錯(cuò),現(xiàn)代系統(tǒng)提供了一種對(duì)主存的抽象概念,叫做虛擬內(nèi)存(VM)。虛擬內(nèi)存是硬件異常、硬件地址翻譯、主存、磁盤文件和內(nèi)核軟件的完美交互,它為每個(gè)進(jìn)程提供了一個(gè)大的、一致的和私有的地址空間。通過(guò)一個(gè)很清晰的機(jī)制,虛擬內(nèi)存提供了三個(gè)重要的能力:
- 它將主存看成是一個(gè)存儲(chǔ)在磁盤上的地址空間的高速緩存,在主存中只保存活動(dòng)區(qū)域,并根據(jù)需要在磁盤和主存之間來(lái)回傳送數(shù)據(jù),通過(guò)這種方式,它高效地使用了主存。
- 它為每個(gè)進(jìn)程提供了一致的地址空間,從而簡(jiǎn)化了內(nèi)存管理。
- 它保護(hù)了每個(gè)進(jìn)程的地址空間不被其他進(jìn)程破壞。
為什么要引入虛擬內(nèi)存?
虛擬內(nèi)存作為緩存的工具
- 虛擬內(nèi)存被組織為一個(gè)由存放在磁盤上的N個(gè)連續(xù)的字節(jié)大小的單元組成的數(shù)組。
- 虛擬內(nèi)存利用DRAM緩存來(lái)自通常更大的虛擬地址空間的頁(yè)面。
虛擬內(nèi)存作為內(nèi)存管理的工具。操作系統(tǒng)為每個(gè)進(jìn)程提供了一個(gè)獨(dú)立的頁(yè)表,也就是獨(dú)立的虛擬地址空間。多個(gè)虛擬頁(yè)面可以映射到同一個(gè)物理頁(yè)面上。
- 一般:每個(gè)進(jìn)程有各自私有的代碼,數(shù)據(jù),堆棧,是不和其他進(jìn)程共享的,這樣OS創(chuàng)建頁(yè)表,將虛擬頁(yè)映射到不連續(xù)的物理頁(yè)面。
- 某些情況下,需要進(jìn)程來(lái)共享代碼和數(shù)據(jù)。例如每個(gè)進(jìn)程調(diào)用相同的操作系統(tǒng)內(nèi)核代碼,或者C標(biāo)準(zhǔn)庫(kù)函數(shù)。OS會(huì)把不同進(jìn)程中適當(dāng)?shù)奶摂M頁(yè)面映射到相同的物理頁(yè)面。
- 加載器從不在磁盤到內(nèi)存實(shí)際復(fù)制任何數(shù)據(jù),在每個(gè)頁(yè)初次被引用時(shí),虛擬內(nèi)存系統(tǒng)會(huì)按照需要自動(dòng)的調(diào)入數(shù)據(jù)頁(yè)。
- 例如:一個(gè)給定的linux系統(tǒng)上的每個(gè)進(jìn)程都是用類似的內(nèi)存格式,對(duì)于64為地址空間,代碼段總是從虛擬地址)0x400000開(kāi)始,數(shù)據(jù)段,代碼段,棧,堆等等。
- 簡(jiǎn)化鏈接: 獨(dú)立的地址空間允許每個(gè)進(jìn)程的內(nèi)存映像使用相同的基本格式,而不管代碼和數(shù)據(jù)實(shí)際存放在物理內(nèi)存的何處。
- 簡(jiǎn)化加載: 虛擬內(nèi)存還使得容易向內(nèi)存中加載可執(zhí)行文件和共享對(duì)象文件。要把目標(biāo)文件中.text和.data節(jié)加載到一個(gè)新創(chuàng)建的進(jìn)程中,Linux加載器為代碼和數(shù)據(jù)段分配虛擬頁(yè)VP,把他們標(biāo)記為無(wú)效(未被緩存) ,將頁(yè)表?xiàng)l目指向目標(biāo)文件的起始位置。
- 簡(jiǎn)化共享: 獨(dú)立地址空間為OS提供了一個(gè)管理用戶進(jìn)程和操作系統(tǒng)自身之間共享的一致機(jī)制。
- 簡(jiǎn)化內(nèi)存分配: 虛擬內(nèi)存向用戶提供一個(gè)簡(jiǎn)單的分配額外內(nèi)存的機(jī)制。當(dāng)一個(gè)運(yùn)行在用戶進(jìn)程中的程序要求額外的堆空間時(shí)(如malloc),OS分配一個(gè)適當(dāng)k大小個(gè)連續(xù)的虛擬內(nèi)存頁(yè)面,并且將他們映射到物理內(nèi)存中任意位置的k個(gè)任意物理頁(yè)面,因此操作系統(tǒng)沒(méi)有必要分配k個(gè)連續(xù)的物理內(nèi)存頁(yè)面,頁(yè)面可以隨機(jī)的分散在物理內(nèi)存中。
虛擬內(nèi)存作為內(nèi)存保護(hù)的工具。不應(yīng)該允許一個(gè)用戶進(jìn)程修改它的只讀段,也不允許它修改任何內(nèi)核代碼和數(shù)據(jù)結(jié)構(gòu),不允許讀寫其他進(jìn)程的私有內(nèi)存,不允許修改任何與其他進(jìn)程共享的虛擬頁(yè)面。每次CPU生成一個(gè)地址時(shí),MMU會(huì)讀一個(gè)PTE,通過(guò)在PTE上添加一些額外的許可位來(lái)控制對(duì)一個(gè)虛擬頁(yè)面內(nèi)容的訪問(wèn)十分簡(jiǎn)單。
常見(jiàn)的頁(yè)面置換算法
當(dāng)訪問(wèn)一個(gè)內(nèi)存中不存在的頁(yè),并且內(nèi)存已滿,則需要從內(nèi)存中調(diào)出一個(gè)頁(yè)或?qū)?shù)據(jù)送至磁盤對(duì)換區(qū),替換一個(gè)頁(yè),這種現(xiàn)象叫做缺頁(yè)置換。當(dāng)前操作系統(tǒng)最常采用的缺頁(yè)置換算法如下:
- 先進(jìn)先出(FIFO)算法:
- 思路:置換最先調(diào)入內(nèi)存的頁(yè)面,即置換在內(nèi)存中駐留時(shí)間最久的頁(yè)面。
- 實(shí)現(xiàn):按照進(jìn)入內(nèi)存的先后次序排列成隊(duì)列,從隊(duì)尾進(jìn)入,從隊(duì)首刪除。
- 特點(diǎn):實(shí)現(xiàn)簡(jiǎn)單;性能較差,調(diào)出的頁(yè)面可能是經(jīng)常訪問(wèn)的
- 最近最少使用(LRU)算法:
- 思路:置換最近一段時(shí)間以來(lái)最長(zhǎng)時(shí)間未訪問(wèn)過(guò)的頁(yè)面。根據(jù)程序局部性原理,剛被訪問(wèn)的頁(yè)面,可能馬上又要被訪問(wèn);而較長(zhǎng)時(shí)間內(nèi)沒(méi)有被訪問(wèn)的頁(yè)面,可能最近不會(huì)被訪問(wèn)。
- 實(shí)現(xiàn):缺頁(yè)時(shí),計(jì)算內(nèi)存中每個(gè)邏輯頁(yè)面的上一次訪問(wèn)時(shí)間,選擇上一次使用到當(dāng)前時(shí)間最長(zhǎng)的頁(yè)面
- 特點(diǎn):可能達(dá)到最優(yōu)的效果,維護(hù)這樣的訪問(wèn)鏈表開(kāi)銷比較大
當(dāng)前最常采用的就是LRU算法。
- 最不常用算法(Least Frequently Used, LFU)
- 思路:缺頁(yè)時(shí),置換訪問(wèn)次數(shù)最少的頁(yè)面
- 實(shí)現(xiàn):每個(gè)頁(yè)面設(shè)置一個(gè)訪問(wèn)計(jì)數(shù),訪問(wèn)頁(yè)面時(shí),訪問(wèn)計(jì)數(shù)加1,缺頁(yè)時(shí),置換計(jì)數(shù)最小的頁(yè)面
- 特點(diǎn):算法開(kāi)銷大,開(kāi)始時(shí)頻繁使用,但以后不使用的頁(yè)面很難置換
請(qǐng)說(shuō)一下什么是寫時(shí)復(fù)制?
- 如果有多個(gè)進(jìn)程要讀取它們自己的那部門資源的副本,那么復(fù)制是不必要的。每個(gè)進(jìn)程只要保存一個(gè)指向這個(gè)資源的指針就可以了。只要沒(méi)有進(jìn)程要去修改自己的“副本”,就存在著這樣的幻覺(jué):每個(gè)進(jìn)程好像獨(dú)占那個(gè)資源。從而就避免了復(fù)制帶來(lái)的負(fù)擔(dān)。如果一個(gè)進(jìn)程要修改自己的那份資源“副本”,那么就會(huì)復(fù)制那份資源,并把復(fù)制的那份提供給進(jìn)程。不過(guò)其中的復(fù)制對(duì)進(jìn)程來(lái)說(shuō)是透明的。這個(gè)進(jìn)程就可以修改復(fù)制后的資源了,同時(shí)其他的進(jìn)程仍然共享那份沒(méi)有修改過(guò)的資源。所以這就是名稱的由來(lái):在寫入時(shí)進(jìn)行復(fù)制。
- 寫時(shí)復(fù)制的主要好處在于:如果進(jìn)程從來(lái)就不需要修改資源,則不需要進(jìn)行復(fù)制。惰性算法的好處就在于它們盡量推遲代價(jià)高昂的操作,直到必要的時(shí)刻才會(huì)去執(zhí)行。
- 在使用虛擬內(nèi)存的情況下,寫時(shí)復(fù)制(Copy-On-Write)是以頁(yè)為基礎(chǔ)進(jìn)行的。所以,只要進(jìn)程不修改它全部的地址空間,那么就不必復(fù)制整個(gè)地址空間。在fork()調(diào)用結(jié)束后,父進(jìn)程和子進(jìn)程都相信它們有一個(gè)自己的地址空間,但實(shí)際上它們共享父進(jìn)程的原始頁(yè),接下來(lái)這些頁(yè)又可以被其他的父進(jìn)程或子進(jìn)程共享。
實(shí)時(shí)操作系統(tǒng)的概念
實(shí)時(shí)操作系統(tǒng)(Real-time operating system, RTOS),又稱即時(shí)操作系統(tǒng),它會(huì)按照排序運(yùn)行、管理系統(tǒng)資源,并為開(kāi)發(fā)應(yīng)用程序提供一致的基礎(chǔ)。實(shí)時(shí)操作系統(tǒng)與一般的操作系統(tǒng)相比,最大的特色就是“實(shí)時(shí)性”,如果有一個(gè)任務(wù)需要執(zhí)行,實(shí)時(shí)操作系統(tǒng)會(huì)馬上(在較短時(shí)間內(nèi))執(zhí)行該任務(wù),不會(huì)有較長(zhǎng)的延時(shí)。這種特性保證了各個(gè)任務(wù)的及時(shí)執(zhí)行。
優(yōu)先級(jí)反轉(zhuǎn)是什么?如何解決
由于多進(jìn)程共享資源,具有最高優(yōu)先權(quán)的進(jìn)程被低優(yōu)先級(jí)進(jìn)程阻塞,反而使具有中優(yōu)先級(jí)的進(jìn)程先于高優(yōu)先級(jí)的進(jìn)程執(zhí)行,導(dǎo)致系統(tǒng)的崩潰。這就是所謂的優(yōu)先級(jí)反轉(zhuǎn)(Priority Inversion)。其實(shí),優(yōu)先級(jí)反轉(zhuǎn)是在高優(yōu)級(jí)(假設(shè)為A)的任務(wù)要訪問(wèn)一個(gè)被低優(yōu)先級(jí)任務(wù)(假設(shè)為C)占有的資源時(shí),被阻塞.而此時(shí)又有優(yōu)先級(jí)高于占有資源的任務(wù)(C)而低于被阻塞的任務(wù)(A)的優(yōu)先級(jí)的任務(wù)(假設(shè)為B)時(shí),于是,占有資源的任務(wù)就被掛起(占有的資源仍為它占有),因?yàn)檎加匈Y源的任務(wù)優(yōu)先級(jí)很低,所以,它可能一直被另外的任務(wù)掛起.而它占有的資源也就一直不能釋放,這樣,引起任務(wù)A一直沒(méi)辦法執(zhí)行.而比它優(yōu)先低的任務(wù)卻可以執(zhí)行。
目前解決優(yōu)先級(jí)反轉(zhuǎn)有許多種方法。其中普遍使用的有2種方法:一種被稱作優(yōu)先級(jí)繼承(priority inheritance);另一種被稱作優(yōu)先級(jí)極限(priority ceilings)。
- 優(yōu)先級(jí)繼承(priority inheritance) 優(yōu)先級(jí)繼承是指將低優(yōu)先級(jí)任務(wù)的優(yōu)先級(jí)提升到等待它所占有的資源的最高優(yōu)先級(jí)任務(wù)的優(yōu)先級(jí).當(dāng)高優(yōu)先級(jí)任務(wù)由于等待資源而被阻塞時(shí),此時(shí)資源的擁有者的優(yōu)先級(jí)將會(huì)自動(dòng)被提升。
- 優(yōu)先級(jí)天花板(priority ceilings)優(yōu)先級(jí)天花板是指將申請(qǐng)某資源的任務(wù)的優(yōu)先級(jí)提升到可能訪問(wèn)該資源的所有任務(wù)中最高優(yōu)先級(jí)任務(wù)的優(yōu)先級(jí).(這個(gè)優(yōu)先級(jí)稱為該資源的優(yōu)先級(jí)天花板)。