iOS中关于dispatch_semaphore_t信号量的一些知识

最近看到一篇关于信号量的文章:

AFNetWorking与dispatch_semaphore_t能共存吗

答案是不能!

作者本来给出了解释, 无奈原答案删除了, 我试着解答一波

原文图片1

先说结论: 发生了死锁!

  • 原因: AFN框架已经把successfailure的回调放在了主线程中. 所以程序在走到dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOEVER)这句代码的时候, 已经将主线程锁住了, 所以同处于主线程的successfailure的回调block压根就不会走, 所以同时放在主线程中的dispatch_semaphore_signal(semaphore)同样也不会走, 那么信号量的
    value值也不可能增大, 所以value值一直为0, 那么被锁住的主线程就永远锁住了.

但是如果使用苹果的NSURLSession的话, 就不会死锁!

原文图片2
  • 原因: 苹果原生的completionHandler回调并没有放在主线程中, 所以当主线程处于等待状态中时, completionHandler依然在异步执行, 当执行完毕时, semaphorevalue+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的回调数据了的.

信号量的方法通常用来管理线程池,
但是一定要注意semaphorevalue值的平衡, 调用了dispatch_semaphore_signal方法, 就需要再某处调用dispatch_semaphore_wait方法, 这有点类似于管理OC对象的引用计数.
但是使用不好也会有诸多不便, 比如由于处理不当, 经常出现主线程死锁的情况. 这样就得不偿失了.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容