最近看到一篇关于信号量的文章:
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对象的引用计数.
但是使用不好也会有诸多不便, 比如由于处理不当, 经常出现主线程死锁的情况. 这样就得不偿失了.