1. 程式人生 > >網路程式設計基礎【day10】:我是一個程序(三)

網路程式設計基礎【day10】:我是一個程序(三)

一、引子

我聽說我的祖先們生活在專用計算機裡, 一生只幫助人類做一件事情,比說微積分運算 了、人口統計了 、生成密碼、甚至通過織布機印花 !  
如果你想在這些專用“計算機”上乾點別的事兒,例如安裝個遊戲玩玩, 那是絕對不可能的, 除非你把它拆掉, 然後建一個全新的機器。  而我這些祖先們勉強可以稱為“程式”。
後來有個叫馮諾依曼的人, 非常了不起, 他提出了“儲存程式”的思想, 並且把計算機分為五大部件: 運算器、控制器、儲存器、輸入裝置、輸出裝置。 
各種各樣不同功能的程式寫好以後,和程式使用的資料一起存放在計算機的儲存器中,即“儲存程式”;然後,計算機按照儲存的程式逐條取出指令加以分析,並執行指令所規定的操作。 
這樣一來,原來的專用計算機變成了通用的計算機,不管你是計算導彈彈道的,模擬核爆炸的,還是計算個人所得稅的, 統統都可以在一臺機器上執行, 我就是其中的一員:  專門計算員工的薪水。

二、程序的誕生

程序的誕生我所在的計算機是個批處理系統, 每次上機時, 我和其他程式都排好隊, 一個接一個的進入記憶體執行。 
每個月末是發薪日, 我都要執行一次,這樣我每月都能見一次CPU阿甘, 這個沉默寡言,但是跑的非常快的傢伙。
我知道記憶體看阿甘不順眼,還告了它一狀,說他一遇到IO操作的時候,就歇著喝茶 ,從來不管不問記憶體和硬碟的忙的要死的慘境。 (碼農翻身注:參見《 CPU阿甘》和《 CPU阿甘之煩惱》)

其實我倒是覺得挺好, 這時候正好和阿甘海闊天空的聊天,他閱程式無數, 知道很多內部訊息,每一個位元組都清清楚楚, 和他聊天實在是爽。 

又到了月末發薪水的時候, 我剛一進入記憶體,便看到這麼一個公告:      

                                                    公告       
    為了建立和諧社會,促進效率和公平, 充分發揮每一個人的能力,經系統黨委慎重研究決定:本系統自即日起,正式從“批處理系統”轉為“多道程式系統”, 希望各部門通力配合,一起完成切換工作。
                                                                                                                    系統黨委
                                                                                                          xxxx年xx月xx日                        
我正想著啥是多道程式系統, 阿甘便打電話給記憶體要我的指令開始運行了。 
和之前一樣,執行到了第13869123行,這是個IO指令, 我歡天喜地的準備和阿甘開聊了。 
阿甘說: 哥們, 準備儲存現場吧, 我要切換到另外一個程式來執行啦!
“啊 ? 我這正執行著呢! 咱們不喝茶了?
“喝啥茶啊,馬上另外一個程式就來了!”
 " 那我什麼時候回來再見你?” 我問道。
“等這個IO指令完成,然後作業系統老大會再給你機會執行的。”
“那誰來記住我當前正在執行第13869123行?  還有剛把兩個資料從記憶體裝載到了你的暫存器,就是那個EAX, EBX , 你一切換豈不都丟了?  ” 我有點著急。
阿甘說:“所以要暫時儲存起來啊, 不僅僅是這些,還有你的那些函式在呼叫過程中形成的棧幀和棧頂, 我這裡用暫存器EBP和ESP維護著, 都得儲存起來。”(碼農翻身注:參見《 CPU阿甘之函式呼叫的祕密》)

“還有” 阿甘接著說,“你開啟的檔案控制代碼,你的程式段和資料段的地址, 你已經使用CPU的時間,等待CPU的時間。。。。。。 以及其他好多好多的東西,統統都要儲存下來。”
我瞪大了眼睛: “這也太麻煩了吧, 原來我只需要關心我的指令和資料, 現在還得整這麼多稀奇古怪的東西”
“沒辦法,這就叫做上下文切換, 把你的工作現場儲存好,這樣下一次執行的時候才能恢復啊。 對了,老大給你們統一起了一個新的名稱:  程序 !   剛才那些需要儲存的東西叫做叫做 程序控制塊 (Processing Control Block,  PCB),”
我想了想,這個名字還挺貼切的, 一個真正進行的程式!  只是這個正在進行的程式隨時可以被打斷啊。 
我只好儲存好上下文,撤出CPU, 回到記憶體裡歇著去了,與此同時另外一個程式開始佔據CPU執行。 
其實我這個程式,奧,不對,我這個程序被放到一個阻塞佇列裡,等到IO的資料來了以後,又被趕到了就緒佇列中, 最後才有機會再次執行,再次見到CPU阿甘。(碼農翻身: 程序的就緒, 阻塞,執行這三個狀態的轉換和《 我是一個執行緒》中描述的非常類似)
阿甘從我的PCB中取出各種儲存的資訊,恢復了執行時現場, 可是忙活了好一陣, 沒辦法,這就是程式切換必須要付出的代價。 
我有點同情阿甘了, 從此以後,他很難再悠閒和和我們海闊天空,每時每刻都處於高速的奔跑中。 
得益於阿甘的高速度, 雖然在同一時刻只有一個程式在執行, 但是有很多程式在短時間內不斷的切換, 在外界看來,  似乎多個程式在同時執行。
尤其是那些速度超慢的人類, 他們開著電腦一邊聽歌,一邊上網,一邊QQ,  很是自在, 理所當然的認為這些程式就是同時在執行。 豈不知阿甘是讓音樂播放器上執行幾十毫秒, 然後打斷,讓瀏覽器程序執行幾十毫秒,再打斷,讓QQ也執行幾十毫秒,如此迴圈往復。 
唉,阿甘真是能者多勞啊, 這個計算機系統也算是達到了我們黨委的目標:兼顧了效率和公平。執行緒有了程序就萬事大吉了嗎? 人類的慾望是無止境的,很快就出現了新情況, 舉個例子來說吧,我有一個兄弟,是個文書處理軟體, 他和我不一樣, 他有介面, 人類在用的時候能看到, 這實在是很幸福, 不像我總是在背後默默工作,幾乎無人知曉。 
這哥們有個智慧的小功能,就是在人類編輯文件的時候能自動儲存, 防止辛辛苦苦敲的文字由於斷電什麼的丟掉。 
可是這個功能導致了人類的抱怨, 原因很簡單,自動儲存文字是和IO打交道,那硬碟有多慢你也知道, 這個時候整個程序就被掛起了, 給人類的感覺就是: 程式死了,鍵盤和滑鼠不響應了! 無法繼續輸入文字, 但是過一會兒就好了。 
並且這種假死一會兒就會出現一次(每當自動儲存的時候), 讓人不勝其煩。 
系統黨委研究了很久, 他們當然可以用兩個程序來解決問題, 一個程序負責和使用者互動, 另外一個程序負責自動儲存, 但是,這兩個程序之間完全是獨立的,每個人都有自己的一畝三分地(地址空間), 完全互不知曉, 程序之間通訊的開銷實在是太大, 他們沒有辦法高效的操作那同一份文件資料。 後來還是勞模阿甘想出了一招 :  可以採用多程序的偉大思想啊!   
把一個程序當成一個資源的容器, 讓裡邊執行幾個輕量級的程序, 就叫 執行緒吧, 這些執行緒共享程序的所有資源, 例如地址空間,全域性變數,檔案資源等等。
但是每個執行緒也有自己獨特的部分, 那就是要記住自己執行到哪一行指令了, 有自己的函式呼叫堆疊,自己的狀態等等, 總而言之,就是為了能像切換程序那樣切換執行緒。 

 

拿我那個哥們的情況來說, 一個程序儲存著文件的資料,  程序中有兩個執行緒, 一個負責和使用者互動, 另外一個專門負責定時的自動儲存,  IO導致的阻塞就不會影響另外一個了。 
注意,這兩個執行緒都能訪問程序的所有東西, 他們兩個要小心,不要發起衝突才好  -- 這是人類程式設計師要做的事情了, 不歸我們管。爭吵阿甘的建議被採納了, 其實這幾乎是唯一的解決問題方式了,  但是由誰來管理引起了激烈爭吵。
系統黨委有一波人堅持要在使用者空間實現執行緒, 換通俗的話說就是讓那些程序在自個兒內部去管理執行緒, 他們的理由也很充分:你們自己實現了執行緒,可以自己定製自己的排程演算法,多靈活啊;  
所有的執行緒切換都在程序內完成, 不用請求我們作業系統核心來處理,效率多高啊;
 況且你們可以在那些核心不支援執行緒的作業系統中執行, 移植性多好啊。 

 

我們清楚的知道這是核心想做甩手掌櫃,  因為他們選擇性的忽略了一個致命的問題: 如果由我們實現執行緒,則作業系統核心還是認為我們只是一個程序而已,對裡邊的執行緒一無所知,對程序的排程還是以程序為最小單位。
一旦出現阻塞的系統呼叫,不僅僅阻塞那個執行緒,還會阻塞整個程序!
例如文書處理器那個程序, 如果負責定時儲存的執行緒發起了IO呼叫, 核心會認為,這是由程序發起的,於是就把整個程序給掛起了, 雖然和使用者互動的程序還是可以執行,也被強制的隨著程序掛起來,不響應了, 這多麼悲催啊, 又回到了老問題上去了。 
所以我們堅決不能答應, 我們則一致的要求:在核心中實現執行緒 ! 核心需要知道程序中執行緒的存在,核心需要維護執行緒表,並且負責排程!

 

黨委的人傲慢的說: 你們不嫌累嗎, 每次建立一個執行緒都得通過我們核心, 多慢啊。
我們說:只有這樣,一個執行緒的IO系統呼叫才不會阻塞我們整個程序啊, 你們完全可以選擇同一個程序的另外一個執行緒去執行。
雙發僵持不下,最後只好妥協, 那就是:混合著實現吧。
使用者空間的程序可以建立執行緒(使用者執行緒), 核心也會建立執行緒(核心執行緒), 使用者執行緒對映到核心執行緒上。

 

問題基本解決了,但也帶來了新的問題,我們的系統也變的越來越複雜, 尤其是程序之間的通訊和執行緒之間的同步, 會那些程式設計師們帶來無窮無盡的煩惱, 這是後話了, 有機會下次再說吧。 

 

注: 本文的插圖來源於《現代作業系統》和《作業系統概念》(恐龍書)這兩本書, 我重畫了一下。 對作業系統感興趣的同學可以看看這兩本書。