iOS gcd dispatch使用注意,dispatch_syn可能产生的死锁
我们在使用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可能产生的死锁的更多相关文章
- iOS 并行编程:GCD Dispatch Sources
1 简介 dispatch source是一种用于处理事件的数据类型,这些被处理的事件为操作系统中的底层级别.Grand Central Dispatch(GCD)支持如下的dispatch sour ...
- iOS GCD基础篇 - 同步、异步,并发、并行的理解
1.关于GCD - GCD全称是Grand Central Dispatch - GCD是苹果公司为多核的并行运算提出的解决方案 - GCD会自动利用更多的CPU内核(比如双核.四核) - GC ...
- iOS GCD之dispatch_semaphore(信号量)
前言 最近在看AFNetworking3.0源码时,注意到在 AFURLSessionManager.m 里面的 tasksForKeyPath: 方法 (L681),dispatch_semapho ...
- iOS 并行编程:GCD Dispatch Queues
1 简介 1.1 功能 Grand Central Dispatch(GCD)技术让任务并行排队执行,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务.任务可以是一个函数 ...
- iOS GCD 编程小结
一.简单介绍 1.GCD简介? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD优势 GCD是苹果公司为多核的并行运算提出的 ...
- iOS GCD 与 NSOperationQueue
NSOperationQueue ios NSOperation vs. GCD StackOverflow: NSOperation vs. Grand Central Dispatch Blog: ...
- iOS——GCD多线程
1> 概述 Grand Central Dispatch (GCD)是Apple开发的一种多核编程技术.主要用于优化应用程序以支持多核处理器以及其他对称多处理系统. GCD提供函数实现多线程开发 ...
- IOS GCD 的理解
GCD (Grand Central Dispatch) 是Apple公司开发的一种技术,它旨在优化多核环境中的并发操作并取代传统多线程的编程模式. 在Mac OS X 10.6和IOS 4.0之后开 ...
- 【精】iOS GCD 具体解释
一.介绍 1.什么是GCD? Grand Central Dispatch.是苹果公司开发的一套多核编程的底层API. GCD首次公布在Mac OS X 10.6,iOS4及以上也可用.GCD存在于l ...
随机推荐
- 页面多次调用查询文章(have_posts())
通常来说一个页面只调用查询一次文章.have_posts() 如果页面,比如首页需要按照不同的查询参数调用多次文章 需要做如下处理: //loop前 $temp_query = $wp_que ...
- vim 使用技巧
2014-11-22 更新 文件abc 1,需要编辑abc的第三行 vim +3 abc 2,需要查询abc文件中的test字符 vim +/test abc 3,创建三个文件 aa bb cc vi ...
- 关于JS的几点TIPS
作为前端基本工作每天都会用到JS...但是我们对JS真的都了解吗,或者说有什么tips是我们不知道的呢.. So..此文关于JS的几点tips..... 一:定时器(可传多个参数) 首先是一个一般的定 ...
- pygal and matplotlib(again)
之前项目有用过pygal做chart图, 写代码很容易,几行代码就很做出一个看上去还不错的chart, 缺点是: 要调的再美观很难, Web上的交互效果较差. 在web上做可视化还是推荐采用Echar ...
- WCF--提示:"未找到终结点。"
刚开始调用WCF的时候一直报错... ““System.ServiceModel.EndpointNotFoundException”类型的异常在 mscorlib.dll 中发生,但未在用户代码中进 ...
- winServer2003除默认端口外的其他端口只能本地访问,关闭防火墙即可
winServer2003除默认端口外的其他端口只能本地访问,关闭防火墙即可
- ThinkPHP3.2.3 安装教程
本文以 Windows 平台为例 安装前准备:Windows操作系统的电脑,php编程环境(配置好了Apache.MySql.php).推荐wampserver. 待安 ...
- Mac Pro 软件收藏
记录下Pro Mac中安装过的软件: 编号 软件名 功能说明 1 QQ 2 微信 3 搜狗输入法 4 Chrome 浏览器 Chrome 及其 插件“个性化设置”备份 5 360云盘 ...
- objective-c-sort-keys-of-nsdictionary-based-on-dictionary-entries
NSArray *keys = [someDictionary allKeys]; NSArray *sortedKeys = [keys sortedArrayUsingComparator:^NS ...
- Javascript高级程序设计——BOM(浏览器对象模型)
BOM(浏览器对象模型),它提供了独立于内容而与浏览器窗口进行交互的对象.BOM由一系列相关的对象构成.一.window对象 window对象表示整个浏览器窗口,但不必表示其中包含的内容.W ...