iOS postNotification死锁问题

最近在项目中又遇到了一个死锁问题,跟NSNotificationCenter有关,这个类平时不知道大家有没有注意过,postNotication的时候是加锁的,如果是在主线程注册对应的监听方法,而此时主线程又在等待另一个线程,则会导致发送通知的线程阻塞。如果发送通知的线程跟等待的线程是同一个,就会导致死锁。

具体情况是这样的,我在项目中使用了libevent库,他有两种运行模式:同步和异步。 如果是同步,则所有操作都在一个线程上执行,如果是异步,则在不同线程上执行,为了避免多线程同时访问同一个导致的崩溃,我们申明了对内部线程进行加锁,即evthread_use_pthreads。

然后我们项目里面申明了一个通知kP2PConnectStatusChangeNoti, 这个通知的回调方法是在MGCameraCollectionViewCell的awakeFromNib方法中注册的(主线程),作用是监听P2P连接的状态,显示对应的UI

然后通知发送的代码是在libevent的一个回调方法session_connect_success中,这个回调方法在p2p连接建立成功后执行

我在离开某个页面的时候,会触发destroy方法,这个方法在主线程执行,然后内部会调用libevent的某些方法,这时候问题来了,当我反复操作离开页面,进入页面(会触发p2p连接的建立)多次后,就出现了死锁。见下图,thread 1 在等待libevent释放锁,livevent在等待thread21 的session_connect_success方法执行完成,而thread21在调用setConnectStatus时,发送kP2PConnectStatusChangeNoti对线程进行了加锁,这个锁是NSNotificationCenter内部加的,我没有具体源码,但是猜测应该是锁住了主线程。 为什么这么说呢? 因为从断点时各线程的情况来看,只有thread1 (主线程)和thread21(libevent线程)在wait,其他线程都没有wait,显然是互相等待导致了死锁。 这里需要注意一点,libevent持有的锁跟NSnotificationCenter内部的锁不是同一个。

我们尝试在主线程异步发送kP2PConnectStatusChangeNoti通知,看还会不会死锁。经过实验证明,这样确实不会死锁,因为是异步的,libevent线程不会被主线程阻塞,也就能顺利的完成event的释放,从而主线程也能顺利运行下去。

那为什么NSNotificationCenter要对postNotification加锁呢?我猜我想应该是为了避免发送通知时,有其他线程对观察者进行添加和移除吧,那样会导致一些意想不到的事情发生,或者是为了避免多线程同时操作内部队列引发数据不一致的问题。我觉得前一种可能性更大,同时addObserver方法和removeObserver内部应该也进行了加锁,这样才能更好的处理多线程同时操作。如果是这样的话,就可以解释为什么postNotification会阻塞主线程了,因为在频繁进入和离开页面的时候,频繁调用了addObserver和removeObserver方法,他们主线程上加了锁(严格来说,removeObserver不一定是在主线程调用,因为这里是编译器自己加上去的,我们并没有显示调用),而postNotification在等待他们释放锁,间接引起了发送通知的线程阻塞。

由此,我们可以得出结论,使用NSNotificationCenter时,发送通知和给通知添加观察者的线程最好是同一个,这样可以避免加锁导致的线程阻塞和App卡死。

相关推荐
报错小能手33 分钟前
Swift EventBus讲解
开发语言·ios·swift
HiDev_4 小时前
iOS 蓝牙开发进阶:彻底理解 CBManager(状态、权限与正确使用方式)
ios·objective-c·蓝牙·ble
文件夹__iOS18 小时前
SwiftUI 核心选型:class + ObservableObject VS struct + @State
ios·swiftui·swift
SameX1 天前
独立开发了一款健康记录 App,聊聊几个让我纠结很久的设计决策
ios
报错小能手1 天前
Swift UI 框架 实战 简易计数器、待办清单 、随机壁纸图库、个人笔记
ui·ios
游戏开发爱好者81 天前
深入理解iOSTime Profiler:提升iOS应用性能的关键工具
android·ios·小程序·https·uni-app·iphone·webview
for_ever_love__2 天前
UI学习:多界面传值的正向传值(属性传值)和反向传值(代理传值)
学习·ui·ios·objective-c
开心就好20252 天前
全面介绍iOS开发工具:Xcode、AppCode、CocoaPods、Fastlane和Git
后端·ios
懋学的前端攻城狮2 天前
数据持久化与缓存策略:在离线与在线间架起桥梁
ios·swift
~央千澈~2 天前
以cocos3.8.8开发的游戏为例商业实战项目举例cocos打包ios苹果安装包ipa完整详细教程-优雅草卓伊凡
ios