1. 程式人生 > >關於《深入理解計算機系統》中“異常控制流”的小故事

關於《深入理解計算機系統》中“異常控制流”的小故事

操作 系統 沒有 老師 假設 按順序 發送信號 吃飯 打勾

  在閱讀《深入理解計算機系統》的第八章“異常控制流”時,可能會出現這樣一種情況:看完這一整章以後都不知道這章到底在講什麽,這章到底有什麽用。這裏我想通過一個生活中的小故事,將一些計算機中的概念轉化為生活中的實例,讓你對這章講述的東西有個大體的了解,避免在閱讀過程中出現不知道它是什麽,不知道它到底有什麽用這樣的情況,從而能夠更好的學習本章的內容。

  這裏我們將人 類比成一臺計算機,人所要做的事情類比成一個程序。一個人一天中可以幹很多事情,比如吃飯、睡覺、做作業,而對於每件事情都有很多步驟。一件事情就相當於一個程序,其中的步驟就相當於一條條指令。對於計算機來說,從給處理器加電到處理器斷電為止,處理器會執行一個個程序。而對於人來說,人從早上起來到晚上睡覺這中間的時間也是在做一件件事情。只要你提前規定好了一天的索要做的事情,你就按照你所規定的事情,一件件執行就行了。而對於人做一件事情來說,可能其中的步驟並不是一直固定不變,按照統一個順序執行下去的,它會根據實際的情況進行調整。就像在做作業時,如果老師要求選做1、2、3題中的任一一題就行了,這時候你就需要根據自己的實際情況,選擇一個自己想做的題,而不是從頭到尾把3道題都做了(這就相當於在一個程序中指令沒有順序執行,而是根據一些變量的情況,使得程序發生了跳轉、返回、調用這些情況)。但是這些都是可以事先規劃好的,也就像一個程序一樣,都是事先寫好,然後再根據執行時的變量選擇相應的執行步驟進行執行的。

  但是這樣的情況並不能完美的描述生活,因為計劃總是趕不上變化的,總有一些意料之外的突發情況,是你在剛開始規劃的時候沒有想到的,會對你當前所做的事情產生影響。比如說在你做作業的時候,你媽媽給你打了個電話,或者說是小夥伴突然找你出去玩,這個時候你不可能邊學習邊打電話,或者說邊學習邊玩(對應於當你在執行一個程序時,遇到一些其他的非編寫程序時所考慮的情況),這時候你必須要去處理掉這些事情。

  而現代系統通過使控制流(即將預先寫好的程序,從頭到尾按順序執行就形成了控制流)發生突變(異常控制流,即通過跳轉到相應的為止來解決異常的情況)來對這些異常情況作出反應。在計算機系統中,異常控制流發生在三個層次:硬件層,操作系統層和軟件層。如下的幾個例子描繪了在不同層所發生的異常,及其相應的處理方式

  比如說,在你寫作業的時候,寫著寫著你的筆突然沒水了(發生故障),這時候你必須拿一支新的筆來解決這樣的情況(異常處理程序),否則你就沒有辦法繼續做作業了。這裏對應的是在硬件層,系統出現了硬件故障,故障事件會使控制轉移到處理程序,處理異常情況。

  又比如說,假設你做作業的習慣不是先把一個作業從頭到尾全部完成了,再去做其他作業。而是換著寫作業,比如先寫寫語文(相當於計劃中的一個任務,對應著計算機中的一個進程),後寫寫數學(計劃中的另一個任務),回過頭再來寫寫語文。這就像操作系統層中,內核通過上下文切換將一個進程轉移到另一個進程執行,這就是操作系統層中的異常控制流。

  現在假設你還有有一個習慣,就是每完成一個作業/一個作業的一部分(相當於發送一個進程發送信號)後,你就會在自己任務單上的相應位置打個勾勾(打勾也算一個任務,這裏就相當於另外一個進程對你的信號做出相應的處理),來表示自己已經完成了這個任務/任務的一部分(這個就相當於在系統中,一個進程向另外一個進程發送一個信號,然後另外一個進程會根據信號的內容進行相應的信號處理)。

  當你在寫數學題時,一個大題下面往往會有很多小題,這裏假設你有一個習慣,就是你每做完一道題,你必須要自己批改才算完成這道題(即做一道題有相應的規則/步驟),然後你會回過頭來再看看大題的描述,再做其他小題,而不是直接做接下來的題。現在有這樣的一個情況,當你在做第一個小題的時候,做到一半的時候,你一看,發現第一個小題的題目弄錯了,這時候你直接可以不用批改(不用完整的完成做題的規則和步驟),什麽也都不管,直接回看大題,然後去做其他的題目。這裏就相當於系統中的非本地跳轉,它可以回避函數調用時的堆棧規則。即每個函數的調用需要一系列的規則/步驟,而非本地跳轉則無視這樣的規則,直接將當前棧的情況恢復到棧的某個歷史時刻的情況,執行那個歷史時刻下堆棧內容中對應的函數,實現控制的轉移(類似於Github中將當前版本直接恢復到歷史版本,從那個歷史版本重新開始)。

關於《深入理解計算機系統》中“異常控制流”的小故事