近期在讀《多處理器編程的藝術》一書,英文版的,最近發現技術類書籍中文翻譯版的品質越來越差,譯者很多都是單純為了錢,其實他們在IT領域很多都是大白,因此還是看原汁原味的英文版吧,雖然吃點力,起碼準確。我利用地鐵上的時間讀了自旋鎖這一章,感覺很有收穫。
自旋鎖在單一處理器非搶佔OS上其實是沒有意義的,只有在多處理器上才有意義,最簡單的自旋鎖就是亂搶的那種,可是所有的處理器上啟動並執行線程都等待同一個變數,會導致所有的爭搶鎖的處理器的cache被重新整理,因此設計者設計出一種新的自旋鎖,每個線程自旋在本處理器的變數上,這樣不會導致所有的處理器重新整理緩衝,該版本自旋鎖的第一個實現就是array鎖,然而array是靜態分配大小的,如果爭搶鎖的線程很少,就會導致空間浪費,於是第二個實現就是隊列鎖,隊列是按需動態擴充的,因此解決了第一個實現中的問題。雖然該種新的自旋鎖避免了cache重新整理,同時又防止了空間浪費,但是會導致饑餓問題,排在後面的爭搶者可能會由於排隊時間過長而損失其響應度,因此一種帶有逾時值的鎖油運而生,這樣就避免了自旋鎖由於排隊長期自旋,總之,只要排隊自旋鎖的隊列過長,那麼就有可能導致饑餓,那麼有沒有什麼辦法限制隊列的長度呢?當然是有的,這就是複合鎖,就是權衡了逾時鎖和排隊鎖的優勢,並且加入了一層新的爭搶的概念,該一層概念類似於令牌,也就是說只有拿到令牌的線程才可以排隊爭搶自旋鎖,令牌的數量是有限的,因此就限制了隊列的長度,如果一個線程拿到了令牌,但是排隊逾時了,那麼它將放棄該令牌,拋出異常,由調用者決定接下來的動作。但是等一下,看看這個鎖有什麼問題,本來是爭搶自旋鎖,現在成了爭搶令牌,這有何意義,其實爭搶令牌是為了讓爭搶鎖更加公平,避免饑餓現象,既然要避免饑餓,那麼打破先來先服務是必要的,這個爭搶令牌的過程就是打破先來先服務的過程,爭搶令牌簡單的使用了退避演算法,為了不使系統在爭搶令牌上開銷過大。如果不是為了在已經避免了饑餓的逾時鎖的基礎上兼顧公平性,逾時鎖已經很不錯了,可是複合鎖進一步加強了公平性,這種公平就是通過打破先來先服務實現的。