與 OSSpinlock相似,使用 dispatch_semaphore 容易形成優先級反轉:html
此 API 沒有記錄當前持有信號量的線程,因此有高優先級的線程在等待鎖時,內核沒法知道該提升哪一個線程的調試優先級(QoS)markdown
若是鎖持有者優先級比其餘線程低,高優先級的等待線程將一直等待app
高效率的線程同步有兩個關鍵點:異步
- 不忙等
- 記錄持有者
自旋鎖是兩點都不符合,dispatch_semaphore 是隻符合不忙等。async
下面先介紹一下 iOS 平臺上的 QoS 概念和優先級反轉避免機制,最後再說明爲何 dispatch_semaphore 不能避免優先級反轉。ide
QoS(Quality of Service),用來指示某任務或隊列的運行優先級。oop
iOS 系統主要使用如下兩種機制來在不一樣線程(或 queue)間傳遞 QoS:ui
機制1:dispatch_asyncspa
機制2:基於 XPC 的進程間通訊(IPC)線程
系統的 QoS 傳遞規則比較複雜,主要參考如下信息:
當前線程的 QoS
若是是使用 dispatch_block_create() 方法生成的 dispatch_block,則考慮生成 block 時所調用的參數
dispatch_async 或 IPC 的目標 queue 或線程的 QoS
調度程序會根據這些信息決定 block 以什麼優先級運行。具體用法請參見QoS使用官方文檔。
若是沒有其餘線程同步地等待此 block,則 block 就按上面所說的優先級來運行。
若是出現了線程間同步等待的狀況,則調度程序會根據狀況調整線程的運行優先級。
優先級反轉:當前線程在同步地等待某個線程(線程1)完成某項操做,而當前線程的優先級比線程1的優先級高。
優先級反轉避免機制(Priority inversion avoidance):若是當前線程因等待某線程(線程1)上正在進行的操做(如 block1)而受阻,而系統知道 block1 所在的目標線程(owner),系統會經過提升相關線程的優先級來解決優先級反轉的問題。
若是系統不知道 block1 所在目標線程,則沒法知道應該提升誰的優先級,也就沒法解決反轉問題
記錄了持有者信息(owner)的系統 API 以下:
pthread mutex、os_unfair_lock、以及基於這兩者實現的其餘上層 API
dispatch_once 的實現是基於 os_unfair_lock 的
NSLock、NSRecursiveLock、@synchronized 等的實現是基於 pthread mutex 的
dispatch_sync()
xpc_connection_send_with_message_sync()
使用以上這些 API 可以在發生優先級反轉時使系統啓用優先級反轉避免機制。
semaphore 不是一個異步方法,因此它沒有 QoS 的概念
在調用 dispatch_semaphore_wait() 時,系統不知道哪一個線程會調用 dispatch_semaphore_signal() 方法,因此係統沒法知道 owner 信息
dispatch_group 跟 semaphore 相似,在調用 enter() 方法時,沒法預知誰會調用 leave(),因此係統也沒法知道其 owner 是誰