iOS 信号量造成线程优先级反转 | 京东云技术团队
在并发队列使用信号量会可能会造成线程优先级反转
一、在 iOS16 & XCode14 上遇到 - 使用信号量造成线程优先级反转问题 提醒
经过查询资料,发现是在 XCode14 上增加了工具,比如 :
Thread Performance Checker (XCode14 上默认开启的),这个工具会让 APP 在运行的时候,发现有例如线程优先级反转和非 UI 工作在主线程上运行等问题的时候,就会在 XCode 问题导航栏中提示该卡顿风险警告,可以帮助我们在开发初期就能发现并解决隐含的卡顿风险问题;这个不是崩溃,如果不想要,可以在 “Product -> Scheme - > Edit Scheme 的 Diagnostics 中去掉 Thread Performance Checker 勾选”
XCode14 还有其他一些新增加的工具类,可参考 iOS卡顿检测
二、关于线程优先级反转
优先级反转(Poiority Inversion) 指高优先级任务需要等待低优先级任务执行完成才能继续执行,这种情况下优先级被反转了。
举例:有三个线程分别为:A、B、C。优先级 A > B > C,线程 A 和 B 处于挂起状态,等待某一事件发生,线程 C 正在运行,此时任务 C 开始使用共享资源 Source。在使用 Source 时,线程 A 等待事件到来,线程 A 转为就绪态,因为线程 A 优先级比线程 C 高,所以线程 A 会立即执行。当线程 A 要使用共享资源 Source 时,由于共享资源 Source 正在被线程 C 使用,因此线程 A 被挂起,线程 C 开始运行。如果此时中等优先级线程 B 等待事件到来,则线程 B 转为就绪态。由于线程 B 优先级比线程 C 高,因此线程 B 开始运行,直到其运行完毕,线程 C 才开始运行。直到线程 C 释放共享资源 Source 后,线程 A 才得以执行。在这种情况下,优先级发生了翻转,线程 B 先于线程 A 运行。
三、优先级反转会造成什么后果
低优先级的任务比高优先级的任务先执行,导致任务的错乱,逻辑错乱;
可能造成系统崩溃;
死锁;优先级低的线程迟迟得不到调度,具有高优先级的线程不能执行,死锁;
四、怎么避免线程优先级反转
如果当前线程因等待某线程上正在进行的 操作如(block1)而受阻,而系统知道 block1 的所在的目标线程,系统会通过提高相关线程的优先级来解决优先级反转的问题 (如线程 A 在尝试获取共享资源而被挂起的期间内,将线程 C 的优先级提升到同线程 A 的优先级,等线程 C 处理结束,降回原优先级,这样能防止 C 被 B 抢占)。如果不知道 block1 所在的目标线程,则无法知道应该提高谁的优先级,也就无法解决反转的问题,如信号量。
五、使用信号量可能会造成线程优先级反转,且无法避免
QoS (Quality of Service),用来指示某任务或者队列的运行优先级;
1、记录了持有者的 api 都可以自动避免优先级反转,系统会通过提高相关线程的优先级来解决优先级反转的问题,如 dispatch_sync, 如果系统不知道持有者所在的线程,则无法知道应该提高谁的优先级,也就无法解决反转问题。
2、慎用 dispatch_semaphore 做线程同步
dispatch_semaphore 容易造成优先级反转,因为 api 没有记录是哪个线程持有了信号量,所以有高优先级的线程在等待锁的时候,内核无法知道该提高那个线程的优先级(QoS);
3、dispatch_semaphore 不能避免优先级反转的原因
在调用 dispatch_semaphore_wait() 的时候,系统不知道哪个线程会调用 dispatch_semaphore_signal()方法,系统无法知道 owner 信息,无法调整优先级。dispatch_group 和 semaphore 类似,在调用 enter()方法的时候,无法预知谁会 leave(),所以系统也不知道 owner 信息
参考资料:
Diagnosing Performance issues early
dispatch_semaphore 会造成优先级反转,慎用!
作者:京东零售 孙巧巧
来源:京东云开发者社区 转载请注明来源
版权声明: 本文为 InfoQ 作者【京东科技开发者】的原创文章。
原文链接:【http://xie.infoq.cn/article/7e9c076c2416b55ff007cbc75】。文章转载请联系作者。
评论