本人有若干成套学习视频, 可试看! 可试看! 可试看, 重要的事情说三遍 包含Java
, 数据结构与算法
, iOS
, 安卓
, python
, flutter
等等, 如有需要, 联系微信tsaievan
.
最近看到一篇关于信号量的文章:
AFNetWorking与dispatch_semaphore_t能共存吗
答案是不能!
作者本来给出了解释, 无奈原答案删除了, 我试着解答一波
原文图片1先说结论: 发生了死锁!
- 原因: AFN框架已经把
success
和failure
的回调放在了主线程中. 所以程序在走到dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOEVER)
这句代码的时候, 已经将主线程锁住了, 所以同处于主线程的success
和failure
的回调block压根就不会走, 所以同时放在主线程中的dispatch_semaphore_signal(semaphore)
同样也不会走, 那么信号量的
value
值也不可能增大, 所以value
值一直为0
, 那么被锁住的主线程就永远锁住了.
但是如果使用苹果的NSURLSession
的话, 就不会死锁!
原文图片2
- 原因: 苹果原生的
completionHandler
回调并没有放在主线程中, 所以当主线程处于等待状态中时,completionHandler
依然在异步执行, 当执行完毕时,semaphore
的value
值+1
, 那么被锁住的线程就被唤醒, 就会继续执行下面的代码, 而不会发生死锁!
其实整个下来就三四个方法:
dispatch_semaphore_t dispatch_semaphore_create(long value);
这个方法就是利用给定的value值创建一个计数信号
信号值必须是>=0
的整数
当不再使用信号时, 必须调用dispatch_release
来释放semaphore
对象
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
这个方法首先将semaphore
对象的信号值-1
, 当semaphore
对象的信号值<0
时, 当前线程锁住(处于休眠状态), 休眠的时间由timeout
参数决定.
DISPATCH_TIME_FOREVER
这个宏表示无限期休眠.
long dispatch_semaphore_signal(dispatch_semaphore_t dsema)
这个方法首先将semaphore
对象的信号值+1
, 当semaphore
对象的信号值>=0
时, 当前线程被唤醒, 得以继续执行队列中的其他任务.
那我们再回到图2的代码:
这段代码中有2个线程: 主线程和session
回调方法所处的子线程.
当子线程中拿不到回调数据的话, 主线程将会一直处于休眠状态.
所以当这段代码中dispatch_semaphore_wait
以下的代码开始执行时, 一定是拿到session
的回调数据了的.
信号量的方法通常用来管理线程池,
但是一定要注意semaphore
的value
值的平衡, 调用了dispatch_semaphore_signal
方法, 就需要再某处调用dispatch_semaphore_wait
方法, 这有点类似于管理OC
对象的引用计数
.
但是使用不好也会有诸多不便, 比如由于处理不当, 经常出现主线程死锁的情况. 这样就得不偿失了.
网友评论