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

相关推荐
传奇开心果编程17 小时前
【Flutter踩坑排雷】第19课:路由硬编码坑|字符串路由书写错误,页面跳转失败排查
android·flutter·ios·移动开发·跨平台·ui框架·声明式ui
茶底世界之下20 小时前
雨后街口的斑马线:用 Awaking 把颜色让给光与步伐
ios·app·产品
茶底世界之下2 天前
晨雾河岸的旧书摊:用 Awaking 给木色一点暖光
ios·app·产品
90后的晨仔2 天前
在 macOS 27 上运行 Xcode 26
ios
茶底世界之下3 天前
山间站台不必转暖:用 Awaking 留住冷光与红箱
ios·app·产品
songgeb4 天前
YYImage Bug:一行之差,正常 JPEG 如何在 iOS 被读成条纹
ios·swift
茶底世界之下4 天前
阴天花摊不必变暖:用 Awaking 留住花色与湿街
ios·app·产品
Fatbobman(东坡肘子)4 天前
快速消失的硬盘容量 -- 肘子的 Swift 周报 #160
开发语言·人工智能·redis·ios·swiftui·iphone·swift
茶底世界之下5 天前
斜光下的旧自行车:用 Awaking 留一版复古胶片色
ios·app·产品