在并發(fā)隊(duì)列使用信號(hào)量會(huì)可能會(huì)造成線程優(yōu)先級(jí)反轉(zhuǎn)
一、在iOS16 & XCode14上遇到 - 使用信號(hào)量造成線程優(yōu)先級(jí)反轉(zhuǎn)問題 提醒
經(jīng)過查詢資料,發(fā)現(xiàn)是在XCode14上增加了工具,比如 :
Thread Performance Checker (XCode14上默認(rèn)開啟的),這個(gè)工具會(huì)讓APP在運(yùn)行的時(shí)候,發(fā)現(xiàn)有例如線程優(yōu)先級(jí)反轉(zhuǎn)和非UI工作在主線程上運(yùn)行等問題的時(shí)候,就會(huì)在XCode問題導(dǎo)航欄中提示該卡頓風(fēng)險(xiǎn)警告,可以幫助我們?cè)陂_發(fā)初期就能發(fā)現(xiàn)并解決隱含的卡頓風(fēng)險(xiǎn)問題;這個(gè)不是崩潰,如果不想要,可以在 “Product -> Scheme - > Edit Scheme 的 Diagnostics 中去掉 Thread Performance Checker勾選”
XCode14還有其他一些新增加的工具類,可參考 iOS卡頓檢測(cè)
二、關(guān)于線程優(yōu)先級(jí)反轉(zhuǎn)
優(yōu)先級(jí)反轉(zhuǎn)(Poiority Inversion) 指高優(yōu)先級(jí)任務(wù)需要等待低優(yōu)先級(jí)任務(wù)執(zhí)行完成才能繼續(xù)執(zhí)行,這種情況下優(yōu)先級(jí)被反轉(zhuǎn)了。
舉例:有三個(gè)線程分別為:A、B、C。優(yōu)先級(jí)A > B > C,線程A和B處于掛起狀態(tài),等待某一事件發(fā)生,線程C正在運(yùn)行,此時(shí)任務(wù)C開始使用共享資源Source。在使用Source時(shí),線程A等待事件到來,線程A轉(zhuǎn)為就緒態(tài),因?yàn)榫€程A優(yōu)先級(jí)比線程C高,所以線程A會(huì)立即執(zhí)行。當(dāng)線程A要使用共享資源Source時(shí),由于共享資源Source正在被線程C使用,因此線程A被掛起,線程C開始運(yùn)行。如果此時(shí)中等優(yōu)先級(jí)線程B等待事件到來,則線程B轉(zhuǎn)為就緒態(tài)。由于線程B優(yōu)先級(jí)比線程C高,因此線程B開始運(yùn)行,直到其運(yùn)行完畢,線程C才開始運(yùn)行。直到線程C釋放共享資源Source后,線程A才得以執(zhí)行。在這種情況下,優(yōu)先級(jí)發(fā)生了翻轉(zhuǎn),線程B先于線程A運(yùn)行。
三、優(yōu)先級(jí)反轉(zhuǎn)會(huì)造成什么后果
低優(yōu)先級(jí)的任務(wù)比高優(yōu)先級(jí)的任務(wù)先執(zhí)行,導(dǎo)致任務(wù)的錯(cuò)亂,邏輯錯(cuò)亂;
可能造成系統(tǒng)崩潰;
死鎖;優(yōu)先級(jí)低的線程遲遲得不到調(diào)度,具有高優(yōu)先級(jí)的線程不能執(zhí)行,死鎖;
四、怎么避免線程優(yōu)先級(jí)反轉(zhuǎn)
如果當(dāng)前線程因等待某線程上正在進(jìn)行的 操作如(block1)而受阻,而系統(tǒng)知道block1的所在的目標(biāo)線程,系統(tǒng)會(huì)通過提高相關(guān)線程的優(yōu)先級(jí)來解決優(yōu)先級(jí)反轉(zhuǎn)的問題 (如線程A在嘗試獲取共享資源而被掛起的期間內(nèi),將線程C的優(yōu)先級(jí)提升到同線程A的優(yōu)先級(jí),等線程C處理結(jié)束,降回原優(yōu)先級(jí),這樣能防止C被B搶占)。如果不知道block1所在的目標(biāo)線程,則無法知道應(yīng)該提高誰的優(yōu)先級(jí),也就無法解決反轉(zhuǎn)的問題,如信號(hào)量。
五、使用信號(hào)量可能會(huì)造成線程優(yōu)先級(jí)反轉(zhuǎn),且無法避免
QoS (Quality of Service),用來指示某任務(wù)或者隊(duì)列的運(yùn)行優(yōu)先級(jí);
1、記錄了持有者的api都可以自動(dòng)避免優(yōu)先級(jí)反轉(zhuǎn),系統(tǒng)會(huì)通過提高相關(guān)線程的優(yōu)先級(jí)來解決優(yōu)先級(jí)反轉(zhuǎn)的問題,如 dispatch_sync, 如果系統(tǒng)不知道持有者所在的線程,則無法知道應(yīng)該提高誰的優(yōu)先級(jí),也就無法解決反轉(zhuǎn)問題。
2、慎用dispatch_semaphore 做線程同步
dispatch_semaphore 容易造成優(yōu)先級(jí)反轉(zhuǎn),因?yàn)閍pi沒有記錄是哪個(gè)線程持有了信號(hào)量,所以有高優(yōu)先級(jí)的線程在等待鎖的時(shí)候,內(nèi)核無法知道該提高那個(gè)線程的優(yōu)先級(jí)(QoS);
3、dispatch_semaphore 不能避免優(yōu)先級(jí)反轉(zhuǎn)的原因
在調(diào)用dispatch_semaphore_wait() 的時(shí)候,系統(tǒng)不知道哪個(gè)線程會(huì)調(diào)用 dispatch_semaphore_signal()方法,系統(tǒng)無法知道owner信息,無法調(diào)整優(yōu)先級(jí)。dispatch_group 和semaphore類似,在調(diào)用enter()方法的時(shí)候,無法預(yù)知誰會(huì)leave(),所以系統(tǒng)也不知道owner信息
參考資料:
優(yōu)先級(jí)反轉(zhuǎn)
優(yōu)先級(jí)反轉(zhuǎn)那些事兒
Diagnosing Performance issues early
dispatch_semaphore 會(huì)造成優(yōu)先級(jí)反轉(zhuǎn),慎用!
作者:京東零售?孫巧巧文章來源:http://www.zghlxwxcb.cn/news/detail-746852.html
來源:京東云開發(fā)者社區(qū) 轉(zhuǎn)載請(qǐng)注明來源文章來源地址http://www.zghlxwxcb.cn/news/detail-746852.html
到了這里,關(guān)于iOS信號(hào)量造成線程優(yōu)先級(jí)反轉(zhuǎn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!