iOS信号量造成线程优先级反转 | 京东云技术团队

京东云开发者
• 阅读 297

在并发队列使用信号量会可能会造成线程优先级反转

一、在iOS16 & XCode14上遇到 - 使用信号量造成线程优先级反转问题 提醒

iOS信号量造成线程优先级反转 | 京东云技术团队

经过查询资料,发现是在XCode14上增加了工具,比如 :

Thread Performance Checker (XCode14上默认开启的),这个工具会让APP在运行的时候,发现有例如线程优先级反转和非UI工作在主线程上运行等问题的时候,就会在XCode问题导航栏中提示该卡顿风险警告,可以帮助我们在开发初期就能发现并解决隐含的卡顿风险问题;这个不是崩溃,如果不想要,可以在 “Product -> Scheme - > Edit Scheme 的 Diagnostics 中去掉 Thread Performance Checker勾选”

iOS信号量造成线程优先级反转 | 京东云技术团队

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 会造成优先级反转,慎用!

作者:京东零售 孙巧巧

来源:京东云开发者社区 转载请注明来源

点赞
收藏
评论区
推荐文章
灯灯灯灯 灯灯灯灯
3年前
Java并发之Semaphore源码解析
Semaphore前情提要在学习本章前,需要先了解ReentrantLock源码解析,ReentrantLock源码解析里介绍的方法有很多是本章的铺垫。下面,我们进入本章正题Semaphore。从概念上来讲,信号量(Semaphore)会维护一组许可证用于限制线程对资源的访问,当我们有一资源允许线程并发访问,但我们希望能限制访问量,就可以用信号量对访问线程
Wesley13 Wesley13
3年前
java四种线程池类型以及可选择的阻塞队列
之前笔记有记录java线程池的拒绝策略,回顾一下线程池的处理任务的优先级:先考虑corePoolSize、任务队列(缓冲队列)workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。即:如果运行的线程少于corePoolSize,则Executor始终首选添加新的线程,而不进行排队
Wesley13 Wesley13
3年前
java线程优先级
java中的线程优先级的范围是1~10,默认的优先级是5。10最高。MIN\_PRIORITY 1MAX\_PRIORITY10NORM\_PRIORITY5优先级高的获得cpu的几率更大些,不是优先级高的就先执行完,线程优先级随机特性在java中,线程的优先级具有继承性,例如A线程启动B线程,则A和B的优先级是一样的线程创建
Wesley13 Wesley13
3年前
java 线程有哪些方法
1.start()启动2.isAlive()是否活动这,只有在start之后,在run方法走完之后,是true3.state()线程状态4.getPriority() 获取线程优先级,默认是5,线程默认优先级为5,如果不手动指定,那么线程优先级具有继承性,比如线程A启动线程B,那么线程B的优先级和线程A的优先级相同5.setPrior
Wesley13 Wesley13
3年前
Java多线程之Semaphore用法
本文目录:Semaphore基本概念Semaphore使用案例:3个停车位,6辆车去抢,走一辆,抢一个停车位。1.Semaphore基本概念在信号量上我们定义两种操作:1.信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。2.acquire(获取)
Wesley13 Wesley13
3年前
Java的编程逻辑
1、run()和start()的区别2、线程的基本属性和方法1.id:一个递增的整数,每创建一个线程就加一2.name3.优先级:从1到10,默认为5,会映射到系统中的优先级。数字越大,要优先级越高4.状态: NEW:还没调用start RUNABLE:正在执行run或者正在等待cup分配
Easter79 Easter79
3年前
SpringCloud之Hystrix服务降级(七)
Hystrix设计原则1.防止单个服务的故障,耗尽整个系统服务的容器(比如tomcat)的线程资源,避免分布式环境里大量级联失败。通过第三方客户端访问(通常是通过网络)依赖服务出现失败、拒绝、超时或短路时执行回退逻辑2.用快速失败代替排队(每个依赖服务维护一个小的线程池或信号量,当线程池满或信号量满,会立即拒绝服务而不会排队等待)和优雅的服
Stella981 Stella981
3年前
Hystrix 服务的隔离策略对比,信号量与线程池隔离的差异
hytrix支持线程池隔离和信号量隔离信号量隔离适应非网络请求,因为是同步的请求,无法支持超时,只能依靠协议本身线程池隔离,即,每个实例都增加个线程池进行隔离先给个总结对比:隔离方式是否支持超时是否支持熔断隔离原理
Wesley13 Wesley13
3年前
Java开发的几个注意点
1\.将一些需要变动的配置写在属性文件中比如,没有把一些需要并发执行时使用的线程数设置成可在属性文件中配置。那么你的程序无论在DEV环境中,还是TEST环境中,都可以顺畅无阻地运行,但是一旦部署在PROD上,把它作为多线程程序处理更大的数据集时,就会抛出IOException,原因也许是线上环境并发造成也许是
Mybatis的parameterType造成线程阻塞问题分析 | 京东云技术团队
最近在新发布某个项目上线时,每次重启都会收到机器的CPU使用率告警,查看对应监控,持续时长达5分钟,对于服务重启有很大风险。而该项目有非常多Consumer消费,服务启动后会有大量线程去拉取消息处理逻辑,通过多次Jstack输出线程快照发现有很多BLOCKED状态线程,此文主要记录分析BLOCKED原因。