【iOS多线程(三)】优先级反转问题

news2024/12/23 5:54:03

优先级反转

实时操作系统的一个基本要求就是基于优先级的抢占系统。保证优先级高的线程在“第一时间”抢到执行权,是实时系统的第一黄金准则。

但是这种基于优先级抢占的系统,有一个著名的问题需要关注,就是“优先级反转”(Priority Inversion),简单来说,就是有低优先级的线程占据了CPU,妨碍了高优先级线程的执行。“优先级反转”是几乎每一个实时操作系统的噩梦,系统设计上花了很多精力去关注,但依然会出错。现代最出名的例子,就是1997美国宇航局的火星探路车(Mars Pathfinder)了。

所以今天就让我们看看优先级反转是怎样发生的,以及对于QNX这样的基于消息传递的操作系统有什么影响。

什么是优先级反转?

概述优先级:线程C>线程B>线程A。优先级较低的线程B,通过压制优先级更低的线程A,比高优先级的线程C先执行了。
解释:假如线程A拿到一个资源后加锁,线程C因为也需要这个资源于是挂起等待A执行结束。这一段符合逻辑没问题,但是此时线程B因为优先级比线程A高,直接抢占CPU,线程B执行完后,线程A执行,A解锁释放后,C再执行。这就导致原本优先级较低的线程B,通过压制线程A,比高优先级的线程C先执行了。

下面这个时序图就是一个经典的优先级反转
在这里插入图片描述

线程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。

优先级反转的后果

低优先级的任务比高优先级的任务先执行,导致任务的错乱,逻辑错乱;

可能造成系统崩溃;

死锁;优先级低的线程迟迟得不到调度,具有高优先级的线程不能执行,死锁;

如何防止优先级反转的方法

其实也不是很复杂,低优先级的A线程获得互斥锁前,需要先将自己的优先级临时提高,最后处理完后再退回原优先级。

set_priority(20);
pthread_mutex_lock();.
pthread mutex unlock();
set_priority(10);

这样在T3的时候,线程虽然有15的优先级,但是对于已经提升到20的线程A无法形成压制,A就会继续执行,直到T5,线程A解锁,线程C立即获得互斥锁并在20上运行,线程B因为优先级低依然无法获取CPU。

在这里插入图片描述

举例:

  1. 优先级反转与QNX

  2. 脉冲的优先级及其继承

  3. QNX上性能优化与优先级继承

在QNX系统开发后期,很多人会面临一个系统性能优化的过程。**如果你以为反正就是看看谁性能太差,把它的优先级提一下就好了,那实在是大错特错了。**从上述关于优先级继承的例子可以看出,在QNX上优先级是“牵一发而动全身”的。有可能你改了某个客户端的优线级,这个优先级会通过消息传递一级一级地传递出去;也有可能,你改的是某个服务器线程的优先级,虽然通过pidin你看到它在优先级22上RECEIVE,但其实一旦收到消息,它会立刻调整自己的优先级,所以修改服务器MsgReceive()线程的优先级是没有什么意义的。

正确的做法一般是,先让各系统都按默认优先级运行。然后针对有问题的部份,用 instrument kernel生成kernel trace,通过kenrel trace来分析在相关时间段内,各个进程的优先级情况,然后对关键进程进行优先级调整。不断重复上述步骤,以达到系统最优状态。

使用信号量可能会造成线程优先级反转,且无法避免

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信息

面试题

1. 什么是优先级反转?请解释其概念并举例说明。

答:
优先级反转是指一个低优先级的任务持有了一个共享资源的锁,而高优先级的任务等待该资源释放,此时中优先级的任务运行并抢占了低优先级的CPU先执行了,会导致高优先级的任务被“反转”到中优先级任务之后运行。

举例:
假设有三个任务A、B、C,它们的优先级分别为高、中、低。任务C持有一个锁并正在运行,任务A需要该锁才能运行,但任务B抢占了CPU时间。这会导致,原本任务A优先级更高,应该在任务B前执行,却导致任务A必须等待任务B完成后才能运行。

2. 在iOS开发中,如何避免或解决优先级反转问题?

答:

    1. 优先级继承 : 确保持有锁的低优先级任务提升到高优先级任务的级别,直到释放锁,再恢复成原来的优先级。(记录了锁持有者的api都可以自动避免优先级反转,系统会通过提高相关线程的优先级来解决优先级反转的问题,如 dispatch_sync)
    1. 避免使用dispatch_semphore(信号量)做线程同步:dispatch_semaphore 容易造成优先级反转,因为api没有记录是哪个线程持有了信号量,所以有高优先级的线程在等待锁的时候,内核无法知道该提高那个线程的优先级(QoS);
    1. 使用合适的锁机制:选择合适的锁机制(如NSLock、NSRecursiveLock等)和避免长时间持有锁。
    1. 避免锁竞争:减少共享资源的使用和锁的粒度,避免长时间锁竞争。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1991020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

优思学院:标准化作业在精益管理之屋中的位置

除了两大支柱,我们必须要对整个精益之屋进行理解,才可以知道精益生产的全貌。精益之屋由4部分组成:地基、2个支柱和屋顶。 首先,地基就是5S活动、目视化管理、标准化作业来建立稳定性。 而标准化作业正正是大家都忽略&#xff0…

计算机网络408考研 2020

2020 湖科大教书匠的个人空间-湖科大教书匠个人主页-哔哩哔哩视频 计算机网络408考研 历年真题解析(有字幕无背景音乐版)_哔哩哔哩_bilibili 计算机网络408考研2020年真题解析_哔哩哔哩_bilibili 1 2 3 41 11 1

cmake 编译教程

一、只有一个源文件的程序编译 首先在当前目录下创建两个文件 hello.cpp CMakeLists.txt (注意CMakeLists大小写,不要写错了) cmake_minimum_required (VERSION 2.8)project (learn_cmake)add_executable(hello hello.cpp) 第一行意思是…

基于R语言绘制GGE双标图4

参考资料: https://cran.r-project.org/web/packages/GGEBiplots/GGEBiplots.pdf 1、数据整理 使用GGEBiplots包绘制双标图,分析用数据是二维数据表(行表示品种或基因型,列表示试验点或环境)。当我们的数据表是一维数…

ip地址是公网还是内网?内网电脑ip地址在哪看

在数字化时代,IP地址作为网络设备的唯一标识符,扮演着至关重要的角色。然而,你是否知道IP地址是内网还是外网?对于内网电脑,我们又该如何快速准确地找到其IP地址呢?下面带着这些疑问跟着虎观代理小二一起深…

《python语言程序设计》2018版第6章第37题,随机生成字符,使用RandomCharacter生成100个小写字母,每行15个

一、正常输出方法设计的代码结构 老规矩用正常输出法设计代码结构 def getRandomCharacter(ch1, ch2):return chr(random.randint(ord(ch1), ord(ch2)))def getRandomLowerCaseLetter():return getRandomCharacter(a, z)count 0 for i in range(100):count 1a getRandomLowe…

深度学习实战(1):树叶分类pytorch

Classify Leaves | Kaggle 上面是数据集 数据导入与数据处理 %matplotlib inline import torch from torch.utils import data as Data import torchvision from torch import nn import torchvision.models as models from IPython import display import os import pandas…

leetcode69. x 的平方根,二分法

leetcode69. x 的平方根 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。 注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0…

培训第二十三天(mysql主从脚本与mysql详细语句介绍)

上午 在同步时,对删除和修改都比较慎重(监控同步时) mysql主从搭建 前提软件libaio,rsync 1、主2、从3、同步4、测试 注意:先执行从服务器的脚本,再执行主服务器脚本 master-mysql配置脚本 先要在主服务…

企元数智小程序合规分销系统赠送:迎接数字化时代商机

当今时代,随着科技的高速发展和数字化的普及,企业如何抓住数字化时代带来的商机,成为了业界关注的焦点。在这样一个竞争激烈的市场环境下,企业需要不断提高自身的竞争力和应变能力,以应对激烈的市场竞争,开…

Phpstorm实现本地SSH开发远程机器(或虚拟机)项目

适用场景: 1、windows系统想要运行仅支持linux、mac系统的项目,可将项目运行在本地虚拟机,但是在虚拟机里使用vim编辑很麻烦,如何实现在本地用Phpstorm来编辑虚拟机中的代码? 下面的说明都是以本地虚拟机为例&#xff…

java之拼图小游戏(开源)

public class LoginJFrame extends JFrame {//表示登录界面,以后所有跟登录相关的都写在这里public LoginJFrame() {//设置界面的长和宽this.setSize(603,680);//设置界面的标题this.setTitle("拼图登陆界面");//设置界面置顶this.setAlwaysOnTop(true);/…

科研绘图系列:R语言圆形条形图(circular barplot)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 介绍 圆形条形图(circular barplot)是一种条形图,其中的条形沿着圆形而不是线性排列展示。这种图表的输入数据集与普通条形图相同:每个组(一个组即一个条形)需要一个数值。(更多解释请参…

linux文件查找--locate和find命令详解

在文件系统上查找符合条件的文件 文件查找:1.非实时查找(数据库查找):locate2.实时查找: find应用:生产环境中查找到系统中占用磁盘空间较大且时间比较久的大日志文件,对这个较大的日志文件做处理(删除移走等),防止它占用更多的磁…

gps 轨迹点如何绘制路径

作为用户,我们进行户外运动后,有的人喜欢分享自己的运动记录。这个时候就比较关注自己的运动轨迹路线了。 一.将经纬度转化为轨迹方法1 1.将gps 打点文件导出。 2.将经纬度点转换成如下格式。 3.将转换后的经纬度填入如下地址: https://ww…

必了解的 20 个 AI 术语解析(下)

AI 领域的基础概念和相关技术有很多,这篇文章里,作者就深入浅出地介绍了相应的内容,感兴趣的同学们,不妨来看一下。 必了解的 20 个 AI 术语解析(下)© 由 ZAKER科技 提供 本文专为非技术背景的 AI 爱…

如何修改360免费wifi热点的频带为2.4G或者5G

有的时候使用电脑广播出热点给嵌入式设备用进而进行抓包,但是他默认广播的是5G Hz的,嵌入式设备扫不到热点。那么如何让他广播2.4G H在呢? CMD控制台使用命令netsh wlan show drivers查看设备驱动: 802.11g 和 802.11n 意味着你的…

Python酷库之旅-第三方库Pandas(071)

目录 一、用法精讲 286、pandas.Series.dt.to_pydatetime方法 286-1、语法 286-2、参数 286-3、功能 286-4、返回值 286-5、说明 286-6、用法 286-6-1、数据准备 286-6-2、代码示例 286-6-3、结果输出 287、pandas.Series.dt.tz_localize方法 287-1、语法 287-2、…

Selenium 自动化测试最佳实践

1 编码前的准备工作与基本指导思想 测试一个网站就是针对该网站测试场景的一次项目开发,所以项目开发中的理念与思想可以借鉴过来。接到测试需求后,不要一开始就陷入按钮、字段、下拉框等页面元素怎么操作的技术细节当中,而要站在最终用户的…

《MySQL数据库》 可视化工具的使用—/—<3>

一、如何使用可视化工具navicat 1、点击左上角的连接中的MySQL 输入主机地址连接虚拟机,找到自己虚拟机中的ip地址输入即可,连接名随意修改 然后点击测试连接,连接成功即可点击确定 2、新建库 直接鼠标右击连接名称ahao001,点击…