2 回答

TA貢獻1898條經驗 獲得超8個贊
這個函數還是十分精妙的!但是有點兒繞
首先糾正一下你代碼的錯誤,while(TestAndSet(&lock))之后是有個分號的,即
while(TestAndSet(&lock));
是個空語句,表示一直在這里死循環。而不是一個勁兒的運行criticalsection。下面說這個機制的原理。
一個線程運行到while(TestAndSet(&lock))這句的時候,
如果criticalsection沒有被鎖住,即lock值為false,那么傳入TestAndSet()的參數為false,【【在函數體內:rv先被賦為false,然后*target被賦為true,然后返回rv(值為false)。運行的結果為:返回值為false,使線程跳出while循環,得以進入criticalsection;同時參數(即lock)被改為true,表示criticalsection被鎖住】】,其他線程在當前線程沒有出criticalsection之前(即運行lock=false這句之前),不能進入criticalsection。為什么呢,下面說
如果線程運行到while(TestAndSet(&lock))時,criticalsection被鎖住了,即lock值為true,那么證明有其他線程在運行criticalsection的代碼(如第一步所說),那么傳入TestAndSet()函數的值為true,《《在函數體內:*target為傳入的值(true),rv被賦為true,*target被賦值為true(原來就是true,賦值不改變什么),返回rv。那么運行結果是返回值是rv(true),lock也是true。因為返回值是true,所以while繼續運行,lock還是true》》,所以傳入TestAndSet()的參數依然是true。在上一句《《》》之間的過程又重新運行一遍,然后一遍又一遍。所以這個線程一直在while這里一直運行,不能進入criticalsection。
直到在criticalsection中的那個線程運行完criticalsection中的代碼,即運行到lock=false這句,lock被賦為false。這時比較關鍵了,while中再次運行TestAndSet()的時候傳入的參數變成了false,那么第一段中【【】】中的過程會運行一遍,即返回值為false,在while中運行了無數次的進程可以跳出while,進入criticalsection,lock又重新被賦為true,即鎖住criticalsection,其他進程此時不能進入。
所以“這條語句”的作用就是:如果當前criticalsection被鎖定,那么在這里等,直到解鎖;如果沒有被鎖定,當前進程可以進入criticalsection,同時鎖定criticalsection。
上面就是原理了,下面說硬同步。
之所以叫硬同步,是因為TestAndSet()函數中的三條語句是由硬件保證同步的,即硬件保證這三條語句必須原子運行,中間不發生任何中斷,如同一條語句。之所以這樣保證,是因為函數體內本身就是一個criticalsection,在多線程程序中,如果在這幾條語句中間被中斷,也會有race condition發生。

TA貢獻1815條經驗 獲得超10個贊
TestAndSet
一個執行單元要想訪問被自旋鎖保護的共享資源,必須先得到鎖,在訪問完共享資源后,必須釋放鎖。如果在獲取自旋鎖時,沒有任何執行單元保持該鎖,那么將立即得到鎖;如果在獲取自旋鎖時鎖已經有保持者,那么獲取鎖操作將自旋在那里,直到該自旋鎖的保持者釋放了鎖。由此可以看出,自旋鎖是一種比較低級的保護數據結構或代碼片段的原始方式,這種鎖可能存在兩個問題:
死鎖。試圖遞歸地獲得自旋鎖必然會引起死鎖:遞歸程序的持有實例在第二個實例循環,以試圖獲得相同自旋鎖時,不會釋放此自旋鎖。在遞歸程序中使用自旋鎖應遵守下列策略:遞歸程序決不能在持有自旋鎖時調用它自己,也決不能在遞歸調用時試圖獲得相同的自旋鎖。此外如果一個進程已經將資源鎖定,那么,即使其它申請這個資源的進程不停地瘋狂“自旋”,也無法獲得資源,從而進入死循環。
過多占用cpu資源。如果不加限制,由于申請者一直在循環等待,因此自旋鎖在鎖定的時候,如果不成功,不會睡眠,會持續的嘗試,單cpu的時候自旋鎖會讓其它process動不了. 因此,一般自旋鎖實現會有一個參數限定最多持續嘗試次數. 超出后, 自旋鎖放棄當前time slice. 等下一次機會。
- 2 回答
- 0 關注
- 129 瀏覽
添加回答
舉報