我们在使用dispatch_sync 时可能会出现死锁,看下面的例子:

import UIKit

class ViewController: UIViewController {
var serialQueue:dispatch_queue_t!
var currentQueue:dispatch_queue_t! override func viewDidLoad() {
super.viewDidLoad() serialQueue = dispatch_queue_create("com.kings.dboperation", DISPATCH_QUEUE_SERIAL)
currentQueue = dispatch_queue_create("com.kings.dboperation", DISPATCH_QUEUE_CONCURRENT) printCurrentThread("main")
      
dispatch_async(serialQueue, {()->Void in
sleep()
self.printCurrentThread("")        //阻塞当前操作,并向serialQueue发出block,等待serialQueue执行完毕这个block,才会解除阻塞,也就是要求提交的block先于外部block完成。
       //但是我们用的是serialQueue,这个queue要求先加入的block必须先完成,也就是要求外部block要先于内部block完成。
       //这就产生了冲突。导致内部的block无法执行,代码锁死在了这里。
       //这里可以看出,dispatch_sync即使在新线程中执行也会由于不小心而产生死锁。
            dispatch_sync(self.serialQueue, {()->Void in
self.printCurrentThread("")
})
self.printCurrentThread("")
})
} func printCurrentThread(prefix:String){
println(prefix + " current thread is \(NSThread.currentThread())")
}
}

输出如下

main   current thread is <NSThread: 0x7bf40950>{number = , name = main}
current thread is <NSThread: 0x7c0fa170>{number = , name = (null)}

程序没有输出2222 和4444的log。详细的解释请看代码中的注视部分。

我们继续试验,换下queue的类型,更改代码如下

dispatch_async(currentQueue, {()->Void in
sleep()
self.printCurrentThread("") dispatch_sync(self.currentQueue, {()->Void in
self.printCurrentThread("")
})
self.printCurrentThread("") })

下面是输出结果

main   current thread is <NSThread: 0x7b7596b0>{number = , name = main}
current thread is <NSThread: 0x7c0298b0>{number = , name = (null)}
current thread is <NSThread: 0x7c0298b0>{number = , name = (null)}
current thread is <NSThread: 0x7c0298b0>{number = , name = (null)}

我们看到,死锁消除了,主要是因为current queue 没有“先放入的block必须先结束” 这个约束!

我们可以看出,在任何时刻都不能在一个向serial queue提交的block中再次利用 dispath_sync向这个serial queue提交block,不然就会产生死锁!


再看把源代码相应部分替换为下面这2段代码,它们都在主线程中执行,第一段,死锁代码,

 dispatch_sync(serialQueue, {()->Void in
sleep()
self.printCurrentThread("")
        
       //参考我们的上面的结论,这里没有向serialQueue继续提交,而是使用了main queue,竟然也死锁了!
dispatch_sync(dispatch_get_main_queue(), {()->Void in
self.printCurrentThread("")
}) self.printCurrentThread("") })

第二段,不死锁代码

dispatch_async(serialQueue, {()->Void in
sleep()
self.printCurrentThread("") dispatch_sync(dispatch_get_main_queue(), {()->Void in
self.printCurrentThread("")
}) self.printCurrentThread("") })

由这2段代码的不同效果,我又尝试了以下代码

    override func viewDidLoad() {
super.viewDidLoad()
dispatch_sync(dispatch_get_main_queue(), {()->Void in
self.printCurrentThread("")
}) }

结果是死锁。

我觉得可以这样理解,viewDidLoad这样的运行在主线程的函数,也是通过GCD机制运行的。viewDidLoad本身就是一个通过sync方法运行在main queue里的代码块,在这个代码块里在用dispatch_sync发送block到同一个queue(这里是main queue),就会产生死锁!上面第二段不死锁的原因就是dispatch_async可以让viewDidload这个代码块不被阻塞,也就不会导致和内部的

dispatch_sync(dispatch_get_main_queue(), {()->Void in
self.printCurrentThread("")
})

这段代码块产生资源竞争了!


问:dispatch_async 一定会建立新线程运行代码,一定不会在main thread中执行吗?

答:目前的测试结果看是这样的。

主线程中调用 + dispatch_async +  Serial Queue           在新线程中执行

主线程中调用 + dispatch_async + Cuncurrent Queue  在新线程中执行

问:dispatch_sync 会建立新线程吗?

答:从我们上面的测试看,dispatch_sync的代码块就执行在dispatch_sync调用时的线程里,具体结论还需要大量测试。

主线程中调用 + dispatch_sync +  Serial Queue  :在主线程中执行

主线程中调用 + dispatch_sync + Cuncurrent Queue  在主线程中执行

Serial Queue 保证的是加入到其中的代码块按顺序执行,并不指定block运行的具体线程。

另外async 和 sync都是针对是否阻塞当前代码块来说的,对block加入queue后的执行没有任何影响。

iOS gcd dispatch使用注意,dispatch_syn可能产生的死锁的更多相关文章

  1. iOS 并行编程:GCD Dispatch Sources

    1 简介 dispatch source是一种用于处理事件的数据类型,这些被处理的事件为操作系统中的底层级别.Grand Central Dispatch(GCD)支持如下的dispatch sour ...

  2. iOS GCD基础篇 - 同步、异步,并发、并行的理解

    1.关于GCD - GCD全称是Grand Central Dispatch  - GCD是苹果公司为多核的并行运算提出的解决方案  - GCD会自动利用更多的CPU内核(比如双核.四核)  - GC ...

  3. iOS GCD之dispatch_semaphore(信号量)

    前言 最近在看AFNetworking3.0源码时,注意到在 AFURLSessionManager.m 里面的 tasksForKeyPath: 方法 (L681),dispatch_semapho ...

  4. iOS 并行编程:GCD Dispatch Queues

    1 简介 1.1 功能          Grand Central Dispatch(GCD)技术让任务并行排队执行,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务.任务可以是一个函数 ...

  5. iOS GCD 编程小结

    一.简单介绍 1.GCD简介? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD优势 GCD是苹果公司为多核的并行运算提出的 ...

  6. iOS GCD 与 NSOperationQueue

    NSOperationQueue ios NSOperation vs. GCD StackOverflow: NSOperation vs. Grand Central Dispatch Blog: ...

  7. iOS——GCD多线程

    1> 概述 Grand Central Dispatch (GCD)是Apple开发的一种多核编程技术.主要用于优化应用程序以支持多核处理器以及其他对称多处理系统. GCD提供函数实现多线程开发 ...

  8. IOS GCD 的理解

    GCD (Grand Central Dispatch) 是Apple公司开发的一种技术,它旨在优化多核环境中的并发操作并取代传统多线程的编程模式. 在Mac OS X 10.6和IOS 4.0之后开 ...

  9. 【精】iOS GCD 具体解释

    一.介绍 1.什么是GCD? Grand Central Dispatch.是苹果公司开发的一套多核编程的底层API. GCD首次公布在Mac OS X 10.6,iOS4及以上也可用.GCD存在于l ...

随机推荐

  1. 软删除脏数据job笔记

    某次处理一个case,发现线上库里有很多数据有问题.于是决定写一个job来将有问题的数据软删除掉.涉及到的两条SQL语句如下: <select id="loadTSKTVBillDai ...

  2. fedora23也会死机, 怎么办

    现在使用的 fedora23 , 在有些 时候老是 死机, 有的是 firefos引起的, 但 更多的时候, 是 由 终端terminal gnome-terminal引起的, 特别是在 操作 vim ...

  3. linux shell中判断bash脚本输入的参数个数

    看下面的一段程序. #!/bin/bash ]; then echo "参数个数为$#个" else echo "没有参数" fi

  4. Vim 的 tab 设置

    文章转自:http://blog.csdn.net/shell_picker/article/details/6033023 摘自 Vim 手册: 选项:1. tabstop:表示一个 tab 显示出 ...

  5. display : -webkit-box-inline 我见

    发现: 最近在做移动端的东西,说起移动端弹性盒子布局真是无往不利,用起来特别爽,我也是偶尔间发现的这个属性并且它的用法,在网上基本查不到这个属性的资料(个人看法).如果没有听说过(display:bo ...

  6. 论Linux运维的一些基础安全知识和简单办法

    不知不觉本人来北京也已经第三个年头了,从一个Linux小小鸟,开始,2012年我参加了第一份工作,其实现在想想其实我是幸运的,本来求学的时候,就没好好的学Linux,我认为有Cisco知识从上wind ...

  7. 性能:15个JavaScript本地存储技术的函数库和工具

    当构建更复杂的JavaScript应用程序运行在用户的浏览器是非常有用的,它可以在浏览器中存储信息,这样的信息可以被共享在不同的页面,浏览会话. 在最近的过去,这将有可能只被cookies文本文件保存 ...

  8. jquery音乐播放器(歌词滚动版)

    好久没出来水了!!!忙忙碌碌的找工作~然后中秋节也算过了,祝各位coding们,直接觉醒第七感小宇宙,直接用心就能找到bug-_-// 最后如题这是一篇很正规的coding的文章 大概么比以前的加了个 ...

  9. 微信或移动端网页的meta

    针对微信: <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> ...

  10. JavaScript-也来谈--闭包

    闭包,以前研究过,可能是当初理解的不够透彻,现在又忘了,(给自己一个台阶下`-...)毕竟js一直没怎么用, 为了防止自己过段时间再忘了,写篇重要的闭包重点, 这样时不时也能温习下知识,不用每次想了解 ...