從溯源角度看:進程間互斥
@[toc]

對多種進程間通信方式的介紹在這篇總結過了:進程間通信,不過沒有提互斥,因為我一直是把互斥和通信分開的。
這一篇的話將從互斥方面入手,按時間線鋪開。這不最近要寫自己寫網絡層了嘛,操作系統的老底子得翻翻。
臨界區
避免競爭條件的問題也可以用一種抽象的方式進行描述,一個進程的一部分時間做內部計算或另外一些不會應發競爭條件的操作。
在某些時候進程可能需要訪問共享內存或共享文件,或執行另外一些會引發競爭的操作。
我們把對共享內存進行訪問的程序片稱作臨界區。
而我們要做的就是通過適當的安排,使得兩個進程不可能同時出在臨界區中,就能避免競爭條件。
對于一個好的解決方案,需要滿足以下4個條件:
任何兩個進程不能同時處于其臨界區; 不應該對CPU的速度和數量做任何假設; 臨界區外運行的進程不得阻塞其他進程
屏蔽中斷
在單處理器的系統中,最簡單的就是使每個進程在剛剛進入臨界區的時候立即屏蔽所有的中斷,并在就要離開之前再打開中斷。屏蔽中斷后,時鐘中斷也被屏蔽。CPU只有在發生時鐘中斷的時候才會進行進程切換,這樣,在屏蔽中斷后CPU就不會被切換到其他進程。
這樣的方案有什么問題嗎?
問題大了。把本該屬于系統內核的權利交給用戶是非常危險的。如果一個屏蔽中斷之后再不打開,會發生什么事情?如果不是單處理器,則屏蔽中斷只會屏蔽某個CPU,而其他CPU依然可能放進程入臨界區。
鎖變量
以前接觸的都是線程鎖,這會兒是進程鎖,其實也是一個道理。玩過單例模式的朋友應該知道二次檢查鎖吧,也知道為什么要二次檢查鎖。
線程鎖有這種紕漏,進程鎖一樣會有這種紕漏。所以這個方案并不是最好的。
先有這個想法,這和我們講的鎖變量不完全是一個東西。
設想有一個鎖變量,其初始值為 TRUE。上鎖的時候怎么上?
1、讀取鎖變量。 2.1、鎖變量的值是TRUE,說明可上鎖。 2.2、鎖變量的值是FALSE,說明不可上鎖。結束,或等待。 3、將鎖變量的值改為FALSE。
既然不是原子操作,就有很多可以插一腳的地方了。不用我多說了。
自旋鎖
看一個案例,兩個進程等待一把自旋鎖:
while(true){ while(turn != 0); //等待 critical_region(); turn = 1; noncritical_region(); }
while(true){ while(turn != 1); //等待 critical_region(); turn = 0; noncritical_region(); }
連續測試一個變量直到某個值出現為止。
如果這時候出現這么一種情況:如果0號進程出了臨界區,將鎖放給1號進程,而一號進程還有一些臨界區外的事務沒有處理完,這就很尷尬了。
只有在有理由認為等待事件是非常短的情況下,才使用自旋鎖。
TSL 指令
特別是那些為并發而生的計算機中,都有這么一條指令:TSL,RX,LOCK
稱為測試并加鎖,它將一個內存字 lock 讀到寄存器 RX 中,然后在該內存地址上存儲一個非零值,讀字操作和寫字操作保證是不可分割的,即該指令結束之前其他處理器均不允許訪問該內存字。執行 TSL 指令的 CPU 將鎖住內存總線,以禁止其他 CPU 在本指令結束前訪問內存。
enter_region: TSL REGISTER,LOCK 復制鎖到寄存器并設置鎖為1 CMP REGISTER,#0 判斷鎖是否為0 JNE enter_region 若不是0,則該鎖已被設置,循環返回調用者,進入臨界區 RET leave_region: MOVE LOCK,#0 在鎖中存入0 RET 返回調用者
一個可替代 TSL 的指令是 XCHG,它原子性的交換了兩個位置的內容,例如:一個寄存器與一個存儲器字。
那這里又出現了新的問題了。這個問題應該說是伴隨互斥而出現的。
進程優先級。在互斥條件下,有可能會出現優先級被倒掛的場景。可能我優先級沒你高,但是我先到,這個坑位我先拿走了,你就擱外邊等著。然后我半天不出來,那就有意思了哈。
我們就是在這樣,一換扣一環的問題解決,發現,解決,發現的過程中成長的,不是嗎?
任務調度
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。