1. 程式人生 > >互斥那點事兒(上)

互斥那點事兒(上)

本年度第 10 次作業系統成員會議開始啦!

一月一度的會議旨在讓大家互相交流,解決最近在工作中出現的問題,以提高整個計算機系統的工作效率。因為計算機硬體在飛速發展,而作業系統是連線計算機硬體和應用程式的中間層,如果故步自封,很快就會被市場淘汰,所以每位作業系統成員都很重視月度會議。

這次提出問題的是程序和執行緒兩兄弟。

站在眾人前面,執行緒顯得有些怯場,他戳了戳程序,示意讓他先來講。程序迅速整理了下思路,挺直了身板,說:“這次的問題是在一個訂票系統裡發現的,我把這個系統的簡單邏輯畫出來了,你們一邊看我一邊說。”

“這個訂票系統分為伺服器端(server)和客戶端(client),當用戶與伺服器建立連線時,伺服器端就會建立一個新的執行緒來為客戶端提供服務。訂票邏輯是這樣的:

單獨從這個邏輯圖上看是沒有問題的,但在實際情況下,因為經常出現多個使用者同時搶訂一張票的情景,這種方式就可能會出錯。就像這樣:

線上程 A 確定完餘票(假設是 1),但還未能成功訂票之前,執行緒 B 得到了餘票數為 1 的資訊,所以 B 也認為可以訂票,最後導致一張票賣出去兩份。“

記憶體一針見血的道:“我看這就是幾個執行緒執行流的衝突問題嘛,本來應該一個執行緒訂票操作結束後,另一個執行緒才能查詢餘票。像這樣執行流交叉,肯定還會出現其它意想不到的問題。”

程序佩服的說:“誒別說,記憶體你說的太有道理了,我也遇到過類似的情況,上次我和另一個程序共享一部分記憶體空間,結果在使用同一個資料的時候,他把我剛寫進去的資料覆蓋掉了,害得我後面的計算全出錯了。”

這時,磁碟發表了他的看法:“執行流的問題,那一看就是程序排程器的鍋,怎麼非得在別人執行到關鍵步驟的時候把人家從 CPU 上趕下來!要是排程器稍微等一會兒,這問題不就解決了?”

程序排程器聽到這話,氣的站起來,說:“你,你怎麼憑空汙人清白!什麼時候切換程序不是由我來決定好不好?我是負責從就緒佇列裡選出最應該使用 CPU 的程序而已。等我開始排程的時候,那些程序就已經被作業系統撤下來了。”

作業系統補充道:“排程器說的沒錯,排程的時機是由中斷決定的。看樣子這種情況出現在程序時間片用盡的時候,出現了時鐘中斷,然後被其他程序搶佔了 CPU 資源。”

磁碟聽了,不好意思的說:“對不起,剛剛是我太武斷了。那照你的意思,我們在執行到這部分程式碼的時候,像這樣遮蔽時鐘中斷可以解決這個問題了?”

作業系統搖搖頭:“「中斷禁用」這種方式確實可以防止程序在執行這部分程式碼時進行切換,但是,時鐘中斷是我的一項非常重要的功能,怎麼能隨隨便便就把控制權交給人類呢?萬一有的程式設計師想要他們的程式碼可以完全佔有 CPU ,不把時鐘中斷給我開啟怎麼辦?我是不可能把這種重要許可權交出去的,我要對整個系統負責。”

記憶體在旁邊贊同道:“除了這一方面,你還要知道,現在都是多核時代了,你即使禁用了這個 CPU 的時鐘中斷,其他幾個核還是能切換程序,然後訪問這些資料。磁碟啊,你明明存了那麼多檔案,怎麼懂得還是那麼少。。。”

磁碟憤憤的道:“別瞧不起我,我這就去找有沒有辦法解決這個問題!”

思考了許久的 CPU 開口了:“我來捋一捋吧,現在咱的目標是,不讓兩個程序同時執行這一段程式碼——我們把這段程式碼叫做臨界區吧,換句話說,我們需要讓程序互斥的進入臨界區。那我們就把這段臨界區「加鎖」,”

“加鎖?這是什麼意思?”

“加鎖是個比喻,其實「鎖」只是一個共享變數,我們可以讓它有 OPENCLOSE 這兩個值。一個程序,比如說 A,進入臨界區之前,先檢查鎖是不是 OPEN 狀態,如果是的話,就把鎖改為 CLOSE 狀態 ,這樣其他程序在進入臨界區時,會發現鎖已經 CLOSE 了,那就讓他們迴圈等待 ,直到 A 出臨界區然後將鎖開啟。”

記憶體眉頭一皺,發現事情並沒有這麼簡單——如果 A 發現鎖是開著的,但在 A 還沒有關閉鎖之前,切換到了程序 B ,那麼 B 也會發現鎖是開著的,那麼 B 也將能夠進入臨界區!

想到這裡,記憶體把問題告訴 CPU,但 CPU 說,這對他不是問題。

原來計算機裡有一條硬體支援的指令——TSL(test and set lock,測試並加鎖),這條指令可以保證讀字和寫字的操作「不可分割」,也就是說,在這條指令結束前,就連其他處理器也不可能訪問該記憶體字。

“TSL 指令會把記憶體字 lock 讀到暫存器上,然後在對應的記憶體地址上寫入一個非零值。那我們就可以利用這條指令改進剛剛的加鎖的方法,就像這樣:

我們讓程序在進入臨界區之前先呼叫 enter_region ,如果鎖已經被關閉(表現為鎖非 0 ),就迴圈呼叫enter_region ,直到鎖開啟,然後再進入臨界區。出臨界區之後,就呼叫 leave_region 把鎖開啟。這樣不就解決你的問題了?“

記憶體點點頭,說:“這確實是一個好方法,解決了臨界區的互斥問題。”

不過作業系統不是很滿意這種解決方案:“這種解決方式需要忙等待,浪費了 CPU 的資源啊,我覺得這種 TSL 方案需要改進。”

這時候大家陷入了沉默——誰也沒有想到更好的解決方案,會議好像就此僵住了。

誰能想到一種更好的方案呢?


哈哈,我在文章裡埋了伏筆哦,你猜猜是誰找到了更好的方法呢?

覺得我寫的還不錯的話,就點個贊吧!

宣告:原創文章,未經授權,禁止轉