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

文章目录

一、前言

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

rust 复制代码
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卡顿检测。

二、关于线程优先级反转

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

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

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 的脚本文件,并编辑其内容。

脚本内容如下:

powershell 复制代码
#!/bin/sh

if [ -n "$XcodeProjectPath" ]; then	
  open -a Terminal "$XcodeProjectPath"/..
else
  open -a Terminal "$XcodeWorkspacePath"/..
fi

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

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

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

powershell 复制代码
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 脚本

脚本内容如下:

powershell 复制代码
#!/bin/sh
# 改脚本用于Xcode 执行快捷键执行 pod install 

path=""
if [ -n "$XcodeProjectPath" ]; then
    path=$XcodeProjectPath
else
    path=$XcodeWorkspacePath	
fi
# 执行 AppleScript 打开 Terminal 进行 podinstall
osascript <<EOF
    tell application "Terminal"
        activate
        do 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 给出如下错误提示信息:

java 复制代码
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缓存
shell 复制代码
rm -rf ~/Library/Developer/Xcode/DerivedData/

2)清理CocoaPods缓存

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

shell 复制代码
rm -rf "${HOME}/Library/Caches/CocoaPods" 
rm -rf "`pwd`/Pods/" 
pod update

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

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

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

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

swift 复制代码
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应用在本地热部署启动过程中,控制台给出以下提示信息:

powershell 复制代码
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。

相关推荐
左钦杨29 分钟前
IOS CSS3 right transformX 动画卡顿 回弹
前端·ios·css3
努力成为包租婆2 小时前
SDK does not contain ‘libarclite‘ at the path
ios
安和昂19 小时前
【iOS】Tagged Pointer
macos·ios·cocoa
I烟雨云渊T1 天前
iOS 阅后即焚功能的实现
macos·ios·cocoa
struggle20251 天前
适用于 iOS 的 开源Ultralytics YOLO:应用程序和 Swift 软件包,用于在您自己的 iOS 应用程序中运行 YOLO
yolo·ios·开源·app·swift
Unlimitedz1 天前
iOS视频编码详细步骤(视频编码器,基于 VideoToolbox,支持硬件编码 H264/H265)
ios·音视频
安和昂2 天前
【iOS】SDWebImage源码学习
学习·ios
ii_best2 天前
按键精灵ios脚本新增元素功能助力辅助工具开发(三)
ios
ii_best2 天前
按键精灵ios脚本新增元素功能助力辅助工具开发(二)
ios
ii_best2 天前
按键精灵ios脚本新增元素功能助力辅助工具开发(一)
ios