程狀態(tài)圖到并發(fā)讀改寫:操作系統(tǒng)習(xí)題答案解析)
簡介面向?qū)W習(xí)操作系統(tǒng)課程、正在對(duì)照《操作系統(tǒng)精髓與設(shè)計(jì)原理》第八版完成課后習(xí)題與復(fù)習(xí)的本科生、考研讀者這份答案資料圍繞進(jìn)程管理、進(jìn)程狀態(tài)轉(zhuǎn)換、進(jìn)程調(diào)度、資源管理和并發(fā)編程等核心知識(shí)點(diǎn)展開可用于核對(duì)解題思路、梳理章節(jié)脈絡(luò)并定位薄弱環(huán)節(jié)。壓縮包內(nèi)共1個(gè)docx文檔大小約904KB內(nèi)容按習(xí)題編號(hào)組織涵蓋就緒態(tài)、運(yùn)行態(tài)、阻塞態(tài)與非常駐態(tài)之間轉(zhuǎn)換事件的說明進(jìn)程調(diào)度中間策略的權(quán)衡分析以及依據(jù)時(shí)刻事件推演進(jìn)程狀態(tài)、判斷阻塞等待事件、分析共享變量并發(fā)執(zhí)行時(shí)輸出順序與取值范圍的解答過程。該資料已有7520人學(xué)習(xí)適合在獨(dú)立完成習(xí)題后對(duì)照參考也便于考前復(fù)盤狀態(tài)轉(zhuǎn)換圖、調(diào)度算法和并發(fā)程序分析等高頻考點(diǎn)。1. 進(jìn)程狀態(tài)圖為什么值得搞懂一臺(tái)電腦里“排隊(duì)”的真相打開任務(wù)管理器幾十個(gè)進(jìn)程同時(shí)在跑而真正在處理器上執(zhí)行的同一時(shí)刻只有那么一兩個(gè)。操作系統(tǒng)習(xí)題答案里反復(fù)出現(xiàn)的那張進(jìn)程狀態(tài)圖說到底就是把“誰在窗口前辦事、誰在椅子上等、誰已經(jīng)被請(qǐng)到門外”畫成一張圖。它回答一個(gè)很樸素的問題某個(gè)進(jìn)程此刻到底在干什么下一秒又會(huì)因?yàn)槭裁幢粨Q下去。學(xué)進(jìn)程管理時(shí)最容易卡住人的往往不是名詞而是箭頭的方向——運(yùn)行什么時(shí)候退回就緒什么時(shí)候滑進(jìn)阻塞為什么有的進(jìn)程會(huì)被整段搬出內(nèi)存。這些箭頭正是這份“操作系統(tǒng)第八版習(xí)題答案”里被問得最多的部分也是后續(xù)調(diào)度、互斥、死鎖所有題目的地基。2. 五個(gè)狀態(tài)與六次轉(zhuǎn)換進(jìn)程從被創(chuàng)建到被掛起經(jīng)歷了什么進(jìn)程管理這一章之所以難是因?yàn)榻滩牧?xí)慣用一張圖概括所有情況而初學(xué)者的第一反應(yīng)是“這些方塊看起來都一樣”。其實(shí)每個(gè)狀態(tài)只回答一件事這個(gè)進(jìn)程現(xiàn)在缺什么。缺處理器是一種情況缺一個(gè)輸入輸出結(jié)果是另一種缺內(nèi)存位置又是第三種。把“缺什么”想清楚六條箭頭自然就順了。2.1 就緒、運(yùn)行、阻塞三個(gè)身份三種等待通俗地說就緒態(tài)是“菜洗好切好了只等灶臺(tái)空出來”運(yùn)行態(tài)是“正在灶上炒”阻塞態(tài)是“炒到一半發(fā)現(xiàn)鹽沒了出門買鹽去”。關(guān)鍵區(qū)別在于就緒態(tài)缺的只有處理器一旦調(diào)度器點(diǎn)名立刻就能跑阻塞態(tài)缺的是別的東西——磁盤讀完、鍵盤輸入、某個(gè)信號(hào)量被釋放——這時(shí)候就算把整臺(tái)機(jī)器的處理器都空著給它它也跑不動(dòng)。由此可以推出四條最基本的轉(zhuǎn)換狀態(tài)轉(zhuǎn)換引發(fā)事件通俗解釋就緒 → 運(yùn)行被分派器選中分到處理器排到了上臺(tái)運(yùn)行 → 就緒進(jìn)程被搶占時(shí)間片用完、更高優(yōu)先級(jí)到達(dá)還沒干完被叫下來重新排隊(duì)運(yùn)行 → 阻塞運(yùn)行中發(fā)生必須等待的事件如發(fā)起磁盤讀主動(dòng)讓出灶臺(tái)去買鹽阻塞 → 就緒等待的事件發(fā)生了如磁盤讀完成產(chǎn)生中斷鹽買回來了重新排隊(duì)等灶臺(tái)這四條里最容易被寫反的是第二條和第三條。區(qū)分方法很簡單看進(jìn)程是“被迫下臺(tái)”還是“主動(dòng)下臺(tái)”。時(shí)間片到了被換走是運(yùn)行轉(zhuǎn)就緒它的活兒還沒干完只是暫時(shí)沒資格占著處理器發(fā)起一次磁盤讀然后等結(jié)果是運(yùn)行轉(zhuǎn)阻塞它自己知道自己跑不下去了。很多課后答案只寫“進(jìn)程被搶占”五個(gè)字但真正的考點(diǎn)在于搶占之后它回到的是就緒隊(duì)列不是阻塞隊(duì)列。這里還有一個(gè)隱藏角色——分派器。調(diào)度策略決定“下一個(gè)該誰”分派器負(fù)責(zé)“把處理器真正交出去”。教材題目里說“由于該進(jìn)程被分派器分派到處理器”強(qiáng)調(diào)的就是這一步是動(dòng)作不是策略。策略和動(dòng)作分開看進(jìn)程調(diào)度那幾道題就不會(huì)混。2.2 掛起態(tài)被搬出內(nèi)存的進(jìn)程去了哪兒第四個(gè)狀態(tài)在教材里叫“非常駐態(tài)”更多地方寫成“掛起態(tài)”細(xì)分還有就緒/掛起和阻塞/掛起兩種。它和阻塞態(tài)最大的不同是位置阻塞態(tài)雖然沒在跑但它的代碼和數(shù)據(jù)還老老實(shí)實(shí)待在內(nèi)存里掛起態(tài)則是整個(gè)進(jìn)程被搬到磁盤上內(nèi)存里可能一點(diǎn)痕跡都不留。為什么要這么干教材給的答案很實(shí)在內(nèi)存里保存的進(jìn)程已經(jīng)達(dá)到上限又有新進(jìn)程要?jiǎng)?chuàng)建或者系統(tǒng)并發(fā)度需要降低。打個(gè)比方餐館里等位的客人太多椅子不夠了只好請(qǐng)一部分人到門外先站著——人還是那些人但占的地方不一樣了。于是多出兩條轉(zhuǎn)換就緒 → 就緒/掛起內(nèi)存緊張或并發(fā)度要降把已經(jīng)準(zhǔn)備好但暫時(shí)輪不上的進(jìn)程挪出去。阻塞 → 阻塞/掛起同樣是內(nèi)存里進(jìn)程太多把正在等的進(jìn)程連同它的等待狀態(tài)一起挪到磁盤上。注意這兩條的原因被教材歸為同一類答題時(shí)不必硬編兩個(gè)理由。真正需要分清的是一個(gè)進(jìn)程被掛起不代表它等的事件消失了。阻塞/掛起的進(jìn)程等的還是那個(gè)磁盤讀完成或者信號(hào)量只是它現(xiàn)在不在內(nèi)存里等事件來了還得先被調(diào)回來才能繼續(xù)。反過來從掛起回到內(nèi)存的那一側(cè)通常叫激活。這一步教材沒有在狀態(tài)圖里細(xì)畫但理解上就是逆過程內(nèi)存騰出位置了或者它等的事件已經(jīng)發(fā)生、需要盡快處理就把它調(diào)回來。答題時(shí)如果題目只問“引發(fā)每個(gè)狀態(tài)轉(zhuǎn)換的事件”把正向六條寫清楚就夠了如果題目追問“那它怎么回來”答“內(nèi)存有空間或事件已就緒時(shí)被激活調(diào)入”即可。這一層想明白后面那些帶時(shí)刻表的長題才不會(huì)亂。2.3 把事件時(shí)間軸翻譯成狀態(tài)一道題背后的還原方法教材里那種“時(shí)刻 5、15、18、20……分別寫出每個(gè)進(jìn)程在時(shí)刻 22、37、47 的狀態(tài)”的題看著嚇人其實(shí)是體力活。它的解題套路只有三步跟查快遞物流差不多。第一步畫一張表。橫軸是進(jìn)程編號(hào)縱軸是時(shí)刻從最早的事件開始往下排。每個(gè)格子先留空等有事件落進(jìn)去再填。第二步把事件翻譯成狀態(tài)變化。這一步靠的是 2.1 和 2.2 那張轉(zhuǎn)換表但要補(bǔ)兩個(gè)教材題里常埋的細(xì)節(jié)請(qǐng)求輸入輸出是運(yùn)行轉(zhuǎn)阻塞輸入輸出完成產(chǎn)生中斷是阻塞轉(zhuǎn)就緒。注意是“完成”才算發(fā)出請(qǐng)求那一刻只是開始等。換出是轉(zhuǎn)入掛起調(diào)入是從掛起回來。中間隔著的那段時(shí)間該進(jìn)程既不占內(nèi)存也不參與調(diào)度。第三步處理“排隊(duì)”這個(gè)坑。同一道題里磁盤單元 3 先后被三個(gè)進(jìn)程碰過一個(gè)進(jìn)程先讀它另一個(gè)進(jìn)程后來要寫它還有一個(gè)進(jìn)程稍后又要讀它。這種共享設(shè)備必須串行使用后來者得等前面的用完。初學(xué)者最容易在這里出錯(cuò)——看到“時(shí)刻 24 某進(jìn)程讀磁盤單元 3”就直接判它阻塞卻忘了它可能還在排隊(duì)等前一個(gè)持有者。判阻塞沒問題但要寫清“等的是磁盤單元 3 空出來”而不是籠統(tǒng)寫“等輸入輸出”。舉個(gè)能確定的小例子某進(jìn)程在時(shí)刻 20 發(fā)起讀磁盤單元 2時(shí)刻 33 產(chǎn)生讀完成中斷那么它在 20 到 33 之間始終是阻塞態(tài)等的就是這次讀完成33 之后轉(zhuǎn)成就緒態(tài)重新排隊(duì)等處理器。同理一個(gè)進(jìn)程時(shí)間片結(jié)束是運(yùn)行轉(zhuǎn)就緒不是轉(zhuǎn)阻塞因?yàn)樗鼪]在等任何外部事件。時(shí)刻表題的答案往往是一長串字母看著像密碼。真正值錢的不是那串字母而是你能不能對(duì)著任意一個(gè)時(shí)刻說出“它為什么在這個(gè)狀態(tài)、它在等誰”。這份習(xí)題答案里給出的狀態(tài)序列配上你自己畫的時(shí)間軸才算真正對(duì)上只抄序列下次換個(gè)時(shí)刻又不會(huì)了。3. 并發(fā)為什么會(huì)算出“錯(cuò)”答案讀改寫從來不是一步單看tally tally 1這一行任何人都會(huì)說結(jié)果加一??梢坏﹥蓚€(gè)進(jìn)程同時(shí)執(zhí)行它結(jié)果就開始不受控制。原因不在代碼寫得對(duì)不對(duì)而在于這行代碼在機(jī)器層面根本不是“一步”。3.1 兩個(gè)進(jìn)程各加 50 次結(jié)果為什么不是 100教材里那道經(jīng)典題兩個(gè)進(jìn)程共享一個(gè)整型變量各自循環(huán) 50 次做自增最后打印這個(gè)變量。按直覺答案應(yīng)該是 100實(shí)際可能小得離譜。因?yàn)橐恍凶栽鼍幾g后通常是三條指令把共享變量讀進(jìn)寄存器、寄存器加一、把寄存器寫回共享變量。# 用生成器模擬兩個(gè)進(jìn)程的指令級(jí)交錯(cuò) # mem 代表共享內(nèi)存reg 代表每個(gè)進(jìn)程私有的寄存器 def total(name, mem): for _ in range(50): reg mem[tally] # LOAD把共享變量讀進(jìn)自己的寄存器 yield # 此處可能被切換到另一個(gè)進(jìn)程 reg 1 # ADD只改自己寄存器里的副本 yield mem[tally] reg # STORE把副本寫回共享變量 yield這段代碼不是真實(shí)實(shí)現(xiàn)只是把“三條指令”和“隨時(shí)可能被切換”這兩件事擺到明面上。關(guān)鍵參數(shù)只有兩個(gè)mem[tally]是大家共用的那一個(gè)格子reg是每個(gè)進(jìn)程各自的小本子。讀的時(shí)候抄一份到自己本子上改的是本子上的數(shù)字只有寫回那一刻才影響大家。問題就出在這兒從抄到寫回之間別人可能已經(jīng)把新數(shù)字寫進(jìn)去了你一寫回就把人家的成果蓋掉了。這正是并發(fā)題目里最反直覺的地方兩個(gè)進(jìn)程都沒有算錯(cuò)各自都老老實(shí)實(shí)做了 50 次加一可最后的結(jié)果卻對(duì)不上。翻車不是因?yàn)檎l寫錯(cuò)了代碼而是因?yàn)椤白x—改—寫”這三步之間存在一個(gè)可以被插隊(duì)的窗口。3.2 上界 100、下界 2 是怎么卡出來的上界好想兩個(gè)進(jìn)程完全錯(cuò)開執(zhí)行一個(gè)做完 50 次另一個(gè)再做 50 次中間沒有任何交錯(cuò)結(jié)果就是 100。這也是最理想的情況說明并發(fā)本身不必然出錯(cuò)只是不保證。下界需要一步步推。設(shè)兩個(gè)進(jìn)程為 A 和 B共享變量初始為 0A 執(zhí)行讀指令把 0 抄進(jìn)自己的寄存器此時(shí)被切走。B 完整跑完 49 次自增共享變量變成 49。A 恢復(fù)執(zhí)行加一自己寄存器里是 1然后寫回共享變量被改成 1——49 被蓋掉了。B 進(jìn)入下一輪讀到的共享變量已經(jīng)是 1抄進(jìn)自己的寄存器。A 一口氣把剩下的自增全部做完共享變量漲到 50。B 執(zhí)行加一寄存器里是 2寫回最終結(jié)果停在 2。所以最終結(jié)果落在 2 到 100 之間。教材進(jìn)一步把它推廣如果有 N 個(gè)這樣的進(jìn)程每個(gè)都做 50 次范圍就本文還有配套的精品資源點(diǎn)擊獲取