iOS开发进阶(六):Xcode14 使用信号量造成线程优先级反转问题修复

本文主要是介绍iOS开发进阶(六):Xcode14 使用信号量造成线程优先级反转问题修复,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 一、前言
    • 二、关于线程优先级反转
    • 三、优先级反转会造成什么后果
    • 四、怎么避免线程优先级反转
    • 五、使用信号量可能会造成线程优先级反转,且无法避免
    • 六、延伸阅读:iOS | Xcode中快速打开终端
      • 6.1 .sh绑定
      • 6.2 执行 `pod install` 脚本
    • 七、延伸阅读:Undefined symbol: _rebind_symbols || symbol(s) not found for architecture arm64
    • 八、延伸阅读: 2 duplicate symbols for architecture arm64
    • 九、延伸阅读:Xcode编译报错:LLDB is likely reading from device memory to resolve symbols.

一、前言

应用Xcode 14.1进行项目编译时,遇到以下错误提示,导致APP线程暂停。

Thread running at QOS_CLASS_USER_INTERACTIVE waiting on a lower QoS thread running at QOS_CLASS_DEFAULT. Investigate ways to avoid priority inversions

在这里插入图片描述

以上问题是由于iOS信号量造成线程优先级反转,在并发队列使用信号量会可能会造成线程优先级反转。

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

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

在这里插入图片描述

XCode14还有其他一些新增加的工具类,可参考 iOS卡顿检测。

二、关于线程优先级反转

优先级反转(Priority 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所在的目标线程,则无法知道应该提高谁的优先级,也就无法解决反转的问题,如信号量。

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

QoSQuality of Service),用来指示某任务或者队列的运行优先级;

  1. 记录了持有者的api都可以自动避免优先级反转,系统会通过提高相关线程的优先级来解决优先级反转问题,如 dispatch_sync, 如果系统不知道持有者所在的线程,则无法知道应该提高谁的优先级,也就无法解决反转问题。

  2. 慎用dispatch_semaphore 做线程同步。dispatch_semaphore 容易造成优先级反转,因为api没有记录是哪个线程持有了信号量,所以有高优先级的线程在等待锁的时候,内核无法知道该提高那个线程的优先级(QoS);

  3. dispatch_semaphore 不能避免优先级反转的原因:在调用dispatch_semaphore_wait() 的时候,系统不知道哪个线程会调用 dispatch_semaphore_signal()方法,系统无法知道owner信息,无法调整优先级。dispatch_groupsemaphore类似,在调用enter()方法的时候,无法预知谁会leave(),所以系统也不知道owner信息。

六、延伸阅读:iOS | Xcode中快速打开终端

AndroidStudioGoland 等 JetBrains IDEA 一系的代码编辑器中,界面底部有一个 Terminal 选项卡。打开选项卡会创建一个 Terminal,并自动切换到当前项目的根目录下,然后我们就可以在此快速的执行一些命令操作。如下图:

在这里插入图片描述

然而,用于 iOS 开发的 Xcode 中并没有该选项卡,这就很不方便了。接下来讲解如何手动为 Xcode 配置一个 Terminal 的快捷入口。

6.1 .sh绑定

步骤1:新建 xcode-terminal.sh 脚本文件

切换到任意目录,然后新建一个 xcode-terminal.sh 的脚本文件,并编辑其内容。

脚本内容如下:

#!/bin/shif [ -n "$XcodeProjectPath" ]; then	open -a Terminal "$XcodeProjectPath"/..
elseopen -a Terminal "$XcodeWorkspacePath"/..
fi

另外,.sh 前面的文件名称可以自定义,但是下面步骤2中修改权限时,名称必须一致。

步骤2:修改文件执行权限

打开终端,并在其中执行如下命令:

chmod +x 路径名/.sh文件名

如: chmod +x xcode-terminal.sh

步骤3:脚本命令添加到 Xcode 中

依次打开 : Xcode menu > Behaviors > Edit Behaviors…,

然后点击下图左下角的 + :

在这里插入图片描述

然后输入自定义的 Behavior 名称(对应上图中的 2),并指定一个快捷键(对应上图中的3)。

然后勾选上图右侧的 Run(对应上图中的4), 并双击 Run 右侧的下拉框(对应上图中的 5 ),指定该 Behavior 对应的脚本文件——也就是刚才创建的 xcode-terminal.sh。

至此,配置完成。在 Xcode 编辑器中,按下自定义的快捷键就可以调出终端了。

6.2 执行 pod install 脚本

脚本内容如下:

#!/bin/sh
# 改脚本用于Xcode 执行快捷键执行 pod install path=""
if [ -n "$XcodeProjectPath" ]; thenpath=$XcodeProjectPath
elsepath=$XcodeWorkspacePath	
fi
# 执行 AppleScript 打开 Terminal 进行 podinstall
osascript <<EOFtell application "Terminal"activatedo script with command "cd \"$path\"/..;pod install"end tell
EOF

总结
任意需求都可以通过脚本实现,然后可以将其关联到 Xcode 的 behavious 中,并为其关联快捷键。

七、延伸阅读:Undefined symbol: _rebind_symbols || symbol(s) not found for architecture arm64

xcode 14 给出如下错误提示信息:

Undefined symbols for architecture arm64:"_rebind_symbols", referenced from:___32+[RCTReconnectingWebSocket load]_block_invoke in libReact-RCTWebSocket.a(RCTReconnectingWebSocket.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

解决方案:

  1. 清理Xcode缓存
rm -rf ~/Library/Developer/Xcode/DerivedData/

2)清理CocoaPods缓存

切换到项目ios目录下,执行以下命令。

rm -rf "${HOME}/Library/Caches/CocoaPods" 
rm -rf "`pwd`/Pods/" 
pod update

若执行 pod update 命令报错,则执行以下命令:

cd ..
pod install --project-directory=ios
  1. 最后将Build Active Architectures Only 设置为NO

八、延伸阅读: 2 duplicate symbols for architecture arm64

编译阶段,错误提示信息如下:

duplicate symbol '_OBJC_CLASS_$_Orientation' in:/Users/ccms-m-03/Library/Developer/Xcode/DerivedData/mrcs-erictiduzoziyxgpkngocqfejvjq/Build/Intermediates.noindex/mrcs.build/Debug-iphoneos/mrcs.build/Objects-normal/arm64/Orientation.o/Users/ccms-m-03/Library/Developer/Xcode/DerivedData/mrcs-erictiduzoziyxgpkngocqfejvjq/Build/Products/Debug-iphoneos/react-native-orientation/libreact-native-orientation.a(Orientation.o)
duplicate symbol '_OBJC_METACLASS_$_Orientation' in:/Users/ccms-m-03/Library/Developer/Xcode/DerivedData/mrcs-erictiduzoziyxgpkngocqfejvjq/Build/Intermediates.noindex/mrcs.build/Debug-iphoneos/mrcs.build/Objects-normal/arm64/Orientation.o/Users/ccms-m-03/Library/Developer/Xcode/DerivedData/mrcs-erictiduzoziyxgpkngocqfejvjq/Build/Products/Debug-iphoneos/react-native-orientation/libreact-native-orientation.a(Orientation.o)
ld: 2 duplicate symbols for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

解决方案:根据提示搜索重复文件Orientation。

若存在重复文件,则删掉一个。

在这里插入图片描述

此外,也可以通过以下步骤检查:

  1. 首先排查是否有名字重复的文件。(查看下自己的项目中创立的文件名和引入的第三方文件名是否重复)。

  2. 检查是否在#import头文件的时候,不小心把.h写成了.m(可以全局搜索是否是这个问题).

  3. 仔细在报错的类中找下是否有重复添加 .h头文件。

九、延伸阅读:Xcode编译报错:LLDB is likely reading from device memory to resolve symbols.

ios应用在本地热部署启动过程中,控制台给出以下提示信息:

Launching “**” is taking longer than expected. Do you want to continue to wait?
LLDB is likely reading from device memory to resolve symbols.

问题分析:
大概意思是编译时间会比预期的要长,是否继续等待。主要是新操作系统和Xcode旧版的架构不匹配造成的。

解决方案:
通过访达,“前往文件夹”功能输入~/Library/Developer/Xcode/,进入iOS DeviceSupport目录,删除该真机对应的架构文件(比如iOS15.1,就删除iOS15.1的架构文件),退出Xcode,拔掉手机,重新连接打开Xcode,解决。

如果上面方案不行,选择Xcode->Window->Devices and Simulators(command+shift+2),鼠标右键点击真机设备,选择Unpair Device。解除信任,然后重新拔插手机,重新信任,重启Xcode。

这篇关于iOS开发进阶(六):Xcode14 使用信号量造成线程优先级反转问题修复的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/610376

相关文章

如何解决idea的Module:‘:app‘platform‘android-32‘not found.问题

《如何解决idea的Module:‘:app‘platform‘android-32‘notfound.问题》:本文主要介绍如何解决idea的Module:‘:app‘platform‘andr... 目录idea的Module:‘:app‘pwww.chinasem.cnlatform‘android-32

使用Python构建一个Hexo博客发布工具

《使用Python构建一个Hexo博客发布工具》虽然Hexo的命令行工具非常强大,但对于日常的博客撰写和发布过程,我总觉得缺少一个直观的图形界面来简化操作,下面我们就来看看如何使用Python构建一个... 目录引言Hexo博客系统简介设计需求技术选择代码实现主框架界面设计核心功能实现1. 发布文章2. 加

kali linux 无法登录root的问题及解决方法

《kalilinux无法登录root的问题及解决方法》:本文主要介绍kalilinux无法登录root的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录kali linux 无法登录root1、问题描述1.1、本地登录root1.2、ssh远程登录root2、

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

使用Python开发一个带EPUB转换功能的Markdown编辑器

《使用Python开发一个带EPUB转换功能的Markdown编辑器》Markdown因其简单易用和强大的格式支持,成为了写作者、开发者及内容创作者的首选格式,本文将通过Python开发一个Markd... 目录应用概览代码结构与核心组件1. 初始化与布局 (__init__)2. 工具栏 (setup_t

SpringBoot应用中出现的Full GC问题的场景与解决

《SpringBoot应用中出现的FullGC问题的场景与解决》这篇文章主要为大家详细介绍了SpringBoot应用中出现的FullGC问题的场景与解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录Full GC的原理与触发条件原理触发条件对Spring Boot应用的影响示例代码优化建议结论F

Python虚拟环境终极(含PyCharm的使用教程)

《Python虚拟环境终极(含PyCharm的使用教程)》:本文主要介绍Python虚拟环境终极(含PyCharm的使用教程),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录一、为什么需要虚拟环境?二、虚拟环境创建方式对比三、命令行创建虚拟环境(venv)3.1 基础命令3

Python Transformer 库安装配置及使用方法

《PythonTransformer库安装配置及使用方法》HuggingFaceTransformers是自然语言处理(NLP)领域最流行的开源库之一,支持基于Transformer架构的预训练模... 目录python 中的 Transformer 库及使用方法一、库的概述二、安装与配置三、基础使用:Pi

关于pandas的read_csv方法使用解读

《关于pandas的read_csv方法使用解读》:本文主要介绍关于pandas的read_csv方法使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录pandas的read_csv方法解读read_csv中的参数基本参数通用解析参数空值处理相关参数时间处理相关

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例