昨天在测试自己写的关于网络请求SDK时候遇到了一个奇葩的问题,具体场景就先不说了,直接回顾下问题发生的原因。
在SDK请求任务时我都会把任务放在单独的线程中,SDK中我只new了这么一个线程暂且叫它SDK线程。
问题来了:
当我发请求任务给SDK线程过程中,请求超时的时候再次发请求,我发现SDK线程不会执行我发请求的这个任务了,也是线程退出或者阻塞了。经过测试发现线程并没有退出而是阻塞了。
具体的原因:
SDK线程被阻塞让我想到的最直接的原因就是里面的用的锁发生死锁导致的。找到是因为这个导致的我就好找代码出错的地方了。在这里我把代码贴出来来看一下。
问题就出现在使用dispatch
的地方。因为我用的队列是一个串行队列,当在使用dispatch_sync的时候一般是不会发生什么问题的,但是当在代码中嵌套使用它的时候就会出现死锁的情况。回到上面描述的问题上,当请求超时的时候我会使用遍历队列这个方法检查是否超时而且在block
中我还使用了超时时需要调用释放资源
这个方法,这时就会产生嵌套的情况(请求超时释放资源这个任务会等待遍历队列任务结束后才会执行但是遍历队列这个任务也在等待释放资源这个任务)。
解决办法:
我当时解决办法就是上面代码中看到的把释放资源这个改为用
dispatch_async
执行任务,那么锁就会直接被释放给遍历队列这个任务,也不影响释放block
的操作。
有没有好的办法避免这种嵌套使用的dispatch_sync
或者打印一些信息给开发人员。那么就会定位问题所在。
下面的方法是我在网上找到的解决方案,我感觉挺不错的。这段代码通过信号量
和dispatch_async
模拟dispatch_sync
。我们可以直接拿这段代码当作dispatch_sync
来使用。用这段代码除了这个用处当发生死锁或者同步的情况时可以打印信息,并且可以设置死锁或者同步了多少时间才打印信息。
注:
以上代码出自
http://www.dreamingwish.com/article/sync-task-safely.html这个站点。