對iOS中自旋鎖與優先順序反轉(Priority inversion)的理解
深入理解代替單純記憶
優先順序反轉
關於優先順序反轉,參考資料中《優先順序反轉那點事兒》講的比較清晰。此處直接貼過來
- 執行緒A在一個比較低的優先順序上工作, 假設是10吧。然後在時間點T1的時候,執行緒A鎖定了一把互斥鎖,並開始操作互斥資料。
- 這時有個高優線級執行緒C(比如優先順序20)在時間點T2被喚醒,它也也需要操作互斥資料。當它加鎖互斥鎖時,因為互斥鎖在T1被執行緒A鎖掉了,所以執行緒C放棄CPU進入阻塞狀態,而執行緒A得以佔據CPU,繼續執行。
- 事情到這一步還是正確的,雖然優先順序10的A執行緒看上去搶了優先順序20的C執行緒的時間,但因為程式邏輯,C確實需要退出CPU等完成互斥資料操作後,才能獲得CPU。
- 但是,假設我們有個執行緒B在優先順序15上,在T3時間點上醒了過來,因為他比當前執行的執行緒A優先順序高,所以它會立即搶佔CPU。而執行緒A被迫進入READY狀態等待。
- 一直到時間點T4,執行緒B放棄CPU,這時優先順序10的執行緒A是唯一READY執行緒,它再次佔據CPU繼續執行,最後在T5解鎖了互斥鎖。
- 在T5,執行緒A解鎖的瞬間,執行緒C立即獲取互斥鎖,並在優先順序20上等待CPU。因為它比執行緒A的優先順序高,系統立刻排程執行緒C執行,而執行緒A再次進入READY狀態。
上面這個時序裡,執行緒B從T3到T4佔據CPU執行的行為,就是事實上的優先順序反轉。一個優先順序15的執行緒B,通過壓制優線級10的執行緒A,而事實上導致高優先順序執行緒C無法正確得到CPU。這段時間是不可控的,因為執行緒B可以長時間佔據CPU(即使輪轉時間片到時,執行緒A和B都處於可執行態,但是因為B的優先順序高,它依然可以佔據CPU),其結果就是高優先順序執行緒C可能長時間無法得到 CPU。
優先順序反轉 vs 自旋鎖
- 優先順序反轉問題的出現跟自旋鎖沒有關係
- 不使用自旋鎖時也可能出現優先順序反轉問題。只要是執行緒或任務有多個優先順序,理論上就可能有反轉問題
- 作業系統在優先順序反轉發生時通常都會有自動的解決方案,比如提高低優先順序執行緒的優先順序等
- 在使用iOS中的
OSSpinLock
時- 由於這種鎖不會記錄持有它的執行緒資訊,所有當發生優先順序反轉時,系統找不到低優先順序的執行緒,可能因此無法通過提高優先順序解決優先順序反轉問題
- 再加上,高優先順序執行緒使用自旋鎖進行輪訓等待鎖時在一直佔用CPU時間片,使得低優先順序執行緒拿到時間片的概率降低
- 總結下來是
- 優先順序反轉問題的出現跟自旋鎖沒有關係
- 但一旦出現優先順序反轉問題,自旋鎖會讓優先順序反轉問題不容易解決,甚至造成更嚴重的執行緒等待問題
atomic和os_unfair_lock
- OSSpinLock被廢棄後,官方建議使用os_unfair_lock代替;
- os_unfair_lock其實是互斥鎖(參考資料中有提到)
- 在老版本中,atomic內部也是用自旋鎖實現的,但後續也改成互斥鎖了
疑惑
- iOS系統中優先順序反轉問題是如何解決的?--參考資料中的蘋果官方文件有提到