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卡死。

相关推荐
jh_cao2 小时前
(3)SwiftUI 的状态之上:数据流与架构(MVVM in SwiftUI)
ios·架构·swiftui
方君宇4 小时前
iOS App小组件(Widget)设置透明背景
ios
恋猫de小郭5 小时前
React 和 React Native 不再直接归属 Meta,React 基金会成立
android·前端·ios
HarderCoder19 小时前
Swift 中的基本运算符:从加减乘除到逻辑与或非
ios·swift
HarderCoder19 小时前
Swift 中“特性开关”实战笔记——用编译条件+EnvironmentValues优雅管理Debug/TestFlight/AppStore三环境
ios·swift
HarderCoder19 小时前
Swift 并发任务中到底该不该用 `[weak self]`?—— 从原理到实战一次讲透
ios·swift
FeliksLv20 小时前
iOS 集成mars xlog
ios
2501_9151063221 小时前
CDN 可以实现 HTTPS 吗?实战要点、部署模式与真机验证流程
网络协议·http·ios·小程序·https·uni-app·iphone
大熊猫侯佩2 天前
在肖申克监狱玩转 iOS 26:安迪的 Liquid Glass 复仇计划
ios·swiftui·swift
非专业程序员2 天前
逆向分析CoreText中的字体级联/Font Fallback机制
前端·ios