一、前言
本篇博文介绍的是iOS中常用的几个多线程技术:
NSThread
GCD
NSOperation
由于apple不提倡开发者直接对线程进行操作,日常开发过程中GCD和NSOperation的使用也较多,因此NSThread会介绍得少些,主要篇幅会放在后面两个。
二、NSThread
2.1 NSThread简介
NSThread是经过apple封装的面向对象的,它允许开发者直接以面向对象的思想对线程进行操作,没一个NSThread对象就代表一条线程,但是开发者必须手动管理线程的生命周期,这点是apple 不提倡的。如果开发者需要手动管理线程时apple提出了以下几点建议:
1、使用GCD和NSOperation
Writing thread-creation code manually is tedious and potentially error-prone and you should avoid it whenever possible. OS X and iOS provide implicit support for concurrency through other APIs
官方文档中说,由于手动管理线程很乏味,并且容易出错,所以apple建议你使用apple自家提供的GCD和NSOperation来进行多线程编程(apple心机婊,说好的手动管理线程的,怎么建议人家使用你的线程自动管理API了呢)。
2、停止长时间在idle状态的线程
remember that threads consume precious system resources.Threads use a nontrivial amount of memory, some of it wired, so releasing an idle thread not only helps reduce your application’s memory footprint, it also frees up more physical memory for other system processes to use
由于线程会占据大量的系统资源,适当的讲长时间处于挂起状态的线程停止,会释放更多的CPU和内存资源。
3、避免让多条线程同时处理一个数据
The simplest and easiest way to avoid thread-related resource conflicts is to give each thread in your program its own copy of whatever data it needs.
使每条线程都操作自己需要操作的数据,如果有必要的话将数据复制一份给另外一条线程处理。
...
如果你真的下定决心要自己管理线程,让Threading Programming Guide帮助你吧。
2.2 NSThread使用:
apple提供了两个方式来使用NSThread:
使用detachNewThreadSelector:toTarget:withObject:
NSThread.detachNewThreadSelector(Selector("thread"), toTarget:self, withObject:nil)
使用initWithTarget:selector:object:方法创建线程,但是必须手动启动:
let thread =NSThread(target:self, selector:Selector("thread") , object:nil)thread.start()
打印结果:
2016-03-23 16:51:51.238 Mutiple[9192:3103867] NSThread-(
"{number = 3, name = (null)}"
)
使用performSelectorInBackground: withObject:方法创建并自动启动
遗憾的是swift无法使用这个方法,原因:
The performSelector: method and related selector-invoking methods are not imported in Swift because they are inherently unsafe.
apple认为这个方法不是类型安全的。
2.3 NSThread几个常用的方法:
//获取主线程和当前线程:NSThread.mainThead()NSThread.currentThread()//退出,取消线程NSThread.exit()thread.cancel()//判断线程状态thread.executing//是否在运行thread.finished//是否结束thread.cancelled//是否取消//判断是否为多线程NSThread.isMultiThread()//使用通知根据线程状态做一些操作NSDidBecomeSingleThreadedNotification//变为单线程NSThreadWillExitNotification//线程即将结束NSWillBecomeMultiThreadedNotification//即将变为多线程//暂停线程
三、GCD
GCD是apple提出的为提高多核效率的多线程实现方案,
This technology takes the thread management code you would normally write in your own applications and moves that code down to the system level. All you have to do is define the tasks you want to execute and add them to an appropriate dispatch queue. GCD takes care of creating the needed threads and of scheduling your tasks to run on those threads
它在系统层级帮助开发者维护线程的生命周期,包括线程的创建、休眠、销毁等,开发者只需要关心需要实现的功能,将需要做的操作放到调度队列(dispatch queue)中,系统会根据线程的情况自动分配资源。
GCD引入了任务(task)和调度队列(dispatch queue)的概念。
所谓的任务,其实就是你要实现的功能和操作,即你要做什么;
调度队列,是实现功能的方式,简单说就是你想怎么做。
apple列举了dispatch queue的许多优点:
提供了更简洁的实现多线程的接口,让代码更简洁
帮开发者管理线程的生命周期
异步队列中不会造成死锁
...
队列中的所有任务都按照FIFO的顺序执行,GCD提供了三种队列:
串行队列
并行队列
主队列
3.1串行队列
创建
使用dispatch_queue_create(label: UnsafePointer, attr: dispatch_queue_attr_t)方法创建队列,来看看apple对方法中的两个属性的解释:
label:
A string label to attach to the queue to uniquely identify it in debugging tools such as Instruments, sample, stackshots, and crash reports. Because applications, libraries, and frameworks can all create their own dispatch queues, a reverse-DNS naming style (com.example.myqueue) is recommended. This parameter is optional and can be NULL.
label是队列的名称,apple推荐使用com.example.myQueue的规则来命名队列,用于debug的时候追踪队列以便于调试,可以为空
attr:
In OS X v10.7 and later or iOS 4.3 and later, specify DISPATCH_QUEUE_SERIAL (or NULL) to create a serial queue or specify DISPATCH_QUEUE_CONCURRENT to create a concurrent queue. In earlier versions, you must specify NULL for this parameter.
attr用于指定是串行队列还是并行队列,如果是NULL则默认串行队列
letserialQ1 = dispatch_queue_create("com.hah.serialQ1",DISPATCH_QUEUE_SERIAL)或者letserialQ2 = dispatch_queue_create("com.hah.serialQ2")
串行队列中的任务会按照FIFO的顺序依次执行,在同步执行下,系统不会开启新的线程,默认在主线程下执行任务,如果是在异步执行下,系统会根据线程资源情况决定是否开启新的线程。
GCD中可以通过串行队列进行锁线程。
来看看同步情况下任务的执行情况:
同步串行:任务一个接着一个执行,不开启新线程;
func syncSerial() {NSLog("=======>>>syncSerial<<<========") let q1 = dispatch_queue_create("q1",DISPATCH_QUEUE_SERIAL)dispatch_sync(q1) { () -> VoidinNSLog("1-%@",NSThread.currentThread()); }dispatch_sync(q1) { () -> VoidinNSLog("2-%@",NSThread.currentThread()); }dispatch_sync(q1) { () -> VoidinNSLog("3-%@",NSThread.currentThread()); }dispatch_sync(q1) { () -> VoidinNSLog("4-%@",NSThread.currentThread()); }dispatch_sync(q1) { () -> VoidinNSLog("5-%@",NSThread.currentThread()]); }NSLog("=======>>>syncSerial<<<========") }
打印结果:
2016-03-23 13:38:29.521 Mutiple[8199:2165063] =======>>>syncSerial<<<========
2016-03-23 13:38:29.522 Mutiple[8199:2165063] 1-(
"{number = 1, name = main}"
)
2016-03-23 13:38:29.522 Mutiple[8199:2165063] 2-(
"{number = 1, name = main}"
)
2016-03-23 13:38:29.522 Mutiple[8199:2165063] 3-(
"{number = 1, name = main}"
)
2016-03-23 13:38:29.523 Mutiple[8199:2165063] 4-(
"{number = 1, name = main}"
)
2016-03-23 13:38:29.523 Mutiple[8199:2165063] 5-(
"{number = 1, name = main}"
)
2016-03-23 13:38:29.523 Mutiple[8199:2165063]
=======>>>syncSerial<<<========
异步串行:任务一个接着一个执行,系统根据线程资源情况决定是否开启新的线程;
func asyncSerail() {NSLog("=======>>>asyncSerail<<<========") let q1 = dispatch_queue_create("q1",DISPATCH_QUEUE_SERIAL)dispatch_async(q1) { () -> VoidinNSLog("1-%@",NSThread.currentThread()); }dispatch_async(q1) { () -> VoidinNSLog("2-%@",NSThread.currentThread()); }dispatch_async(q1) { () -> VoidinNSLog("3-%@",NSThread.currentThread()); }dispatch_async(q1) { () -> VoidinNSLog("4-%@",NSThread.currentThread()); }dispatch_async(q1) { () -> VoidinNSLog("5-%@",NSThread.currentThread()); }NSLog("=======>>>asyncSerail<<<========") }
打印结果:
2016-03-23 13:04:26.713 Mutiple[7294:1959223] =======>>>asyncSerail<<<========
2016-03-23 13:04:26.714 Mutiple[7294:1959223] =======>>>asyncSerail<<<========
2016-03-23 13:04:26.715 Mutiple[7294:1959473] 1-(
"{number = 3, name = (null)}"
)
2016-03-23 13:04:26.716 Mutiple[7294:1959473] 2-(
"{number = 3, name = (null)}"
)
2016-03-23 13:04:26.716 Mutiple[7294:1959473] 3-(
"{number = 3, name = (null)}"
)
2016-03-23 13:04:26.716 Mutiple[7294:1959473] 4-(
"{number = 3, name = (null)}"
)
2016-03-23 13:04:26.716 Mutiple[7294:1959473] 5-(
"{number = 3, name = (null)}"
)
从打印可以看出,系统开启了新的线程,但是所有的任务都是在同一个线程里完成,避免在多个线程之间切换。
3.2 并行队列
并行队列,是全局队列的一种,它能处理并发任务。apple提供了四个已经创建好的并行队列,又叫全局队列(global queu),开发者只需要调用dispatch_get_global_queue( , )就能得到一个并行队列。并行队列同样按照FIFO的原则执行任务,它允许多个任务一起执行,同时执行的任务数量系统会根据情况决定。iOS5以后,apple也允许开发者自己创建并行队列。
3.2.1 获取全局队列:
调用dispatch_get_global_queue(identifier: Int, flags: UInt)方法获取全局队列:
两个参数:
identifier:
The quality of service you want to give to tasks executed using this queue. Quality-of-service helps determine the priority given to tasks executed by the queue. Queues that handle user-interactive or user-initiated tasks have a higher priority than tasks meant to run in the background.
identifier用于指定全局队列的优先级,有4种类型:
#defineDISPATCH_QUEUE_PRIORITY_HIGH2#defineDISPATCH_QUEUE_PRIORITY_DEFAULT0#defineDISPATCH_QUEUE_PRIORITY_LOW (-2)#defineDISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
iOS 8以后可以通过:
QOS_CLASS_USER_INTERACTIVE,
QOS_CLASS_USER_INITIATED,
QOS_CLASS_UTILITY
QOS_CLASS_BACKGROUND.
来设置优先级。
从字面上就能看出,优先级的高低顺序为:DISPATCH_QUEUE_PRIORITY_HIGH>DISPATCH_QUEUE_PRIORITY_DEFAULT>DISPATCH_QUEUE_PRIORITY_LOW>DISPATCH_QUEUE_PRIORITY_BACKGROUND
需要特别说一下的是,系统建议将有关磁盘的I/0操作放到DISPATCH_QUEUE_PRIORITY_BACKGROUND优先级的队列中,防止占用过多的系统资源。
flags :
Flags that are reserved for future use. Always specify 0 for this parameter.
flag默认是0
lethighQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0)//默认优先级也可以这么写:letdefaultQ = dispatch_get_global_queue(0,0)letdefaultQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)letlowQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0)letbgQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0)
我写了段代码模拟了下优先级高的队列先执行的情况:
func queuePriority() { let highQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0) let defaultQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)dispatch_async(defaultQ) { () -> VoidinNSLog("task3 start-%@",NSThread.currentThread()); }dispatch_async(highQ) { () -> VoidinNSLog("task1 start-%@",NSThread.currentThread()); } }
按理说,应该是先执行task1,因为它优先级比较高,但是log是这样的:
2016-03-24 16:12:49.308 Mutiple[3815:2019744] task3 start-(
"{number = 3, name = (null)}"
)
2016-03-24 16:12:49.308 Mutiple[3815:2019743] task1 start-(
"{number = 4, name = (null)}"
)
优先级高的不先执行了,why?
我用优先级high和low做了实验,发现high优先级总是先执行,但是default为什么就不行呢?这个暂时还不明白。
3.2.2 手动创建并行队列
接下来手动创建一个并行队列,查看线程的创建情况:
同步并行:任务一个接着一个执行,系统默认不开启新线程;
func syncConcurrency() {NSLog("=======>>>syncConcurrency<<<========") let q1 = dispatch_queue_create("q1",DISPATCH_QUEUE_CONCURRENT)dispatch_sync(q1) { () -> VoidinNSLog("1-%@",NSThread.currentThread()); }dispatch_sync(q1) { () -> VoidinNSLog("2-%@",NSThread.currentThread()); }dispatch_sync(q1) { () -> VoidinNSLog("3-%@",[NSThread.currentThread()]); }dispatch_sync(q1) { () -> VoidinNSLog("4-%@",NSThread.currentThread()); }dispatch_sync(q1) { () -> VoidinNSLog("5-%@",NSThread.currentThread()); }NSLog("=======>>>syncConcurrency<<<========") }
打印结果:
2016-03-23 13:40:16.968 Mutiple[8256:2181632] =======>>>syncConcurrency<<<========
2016-03-23 13:40:16.969 Mutiple[8256:2181632] 1-(
"{number = 1, name = main}"
)
2016-03-23 13:40:16.970 Mutiple[8256:2181632] 2-(
"{number = 1, name = main}"
)
2016-03-23 13:40:16.970 Mutiple[8256:2181632] 3-(
"{number = 1, name = main}"
)
2016-03-23 13:40:16.970 Mutiple[8256:2181632] 4-(
"{number = 1, name = main}"
)
2016-03-23 13:40:16.970 Mutiple[8256:2181632] 5-(
"{number = 1, name = main}"
)
2016-03-23 13:40:16.970 Mutiple[8256:2181632] =======>>>syncConcurrency<<<========
从打印输出可以看出,所有任务都是在主线程中完成,因为同步执行,即使开了多个线程,下一个的任务还是要等待当前任务执行完毕才能开始执行,开多个线程之后造成资源浪费。就像iOS多线程浅汇-原理篇中讲到的,如果这个时候开了三条线程,系统就必须在三条线程之间切换,除此之外,每条线程都有自己的栈和寄存器,三条线程就有三组的栈和寄存器被复制和替换,这相对于只有一条线程来说,效率肯定是大大降低的。
异步并行:多个任务一起执行,顺序不固定,但是可以通过dispatch_group和NSOperation添加依赖控制任务执行顺序。
func asyncConcurrency() {NSLog("=======>>>asyncConcurrency<<<========") let q1 = dispatch_queue_create("q1",DISPATCH_QUEUE_CONCURRENT)dispatch_async(q1) { () -> VoidinNSLog("1-%@",NSThread.currentThread()); }dispatch_async(q1) { () -> VoidinNSLog("2-%@",NSThread.currentThread(); }dispatch_async(q1) { () -> VoidinNSLog("3-%@",NSThread.currentThread()); }dispatch_async(q1) { () -> VoidinNSLog("4-%@",NSThread.currentThread()); }dispatch_async(q1) { () -> VoidinNSLog("5-%@",NSThread.currentThread()); }NSLog("=======>>>asyncConcurrency<<<========") }
打印结果:
2016-03-23 13:30:20.987 Mutiple[8107:2109033] =======>>>asyncConcurrency<<<========
2016-03-23 13:30:20.988 Mutiple[8107:2109033] =======>>>asyncConcurrency<<<========
2016-03-23 13:30:20.989 Mutiple[8107:2109139] 5-(
"{number = 7, name = (null)}"
)
2016-03-23 13:30:20.989 Mutiple[8107:2109119] 3-(
"{number = 4, name = (null)}"
)
2016-03-23 13:30:20.989 Mutiple[8107:2109093] 1-(
"{number = 3, name = (null)}"
)
2016-03-23 13:30:20.989 Mutiple[8107:2109118] 2-(
"{number = 5, name = (null)}"
)
2016-03-23 13:30:20.990 Mutiple[8107:2109138] 4-(
"{number = 6, name = (null)}"
)
异步下创建多个串行队列实现并行效果
func multiAsyncSerail() {NSLog("=======>>>asyncSerail<<<========") let q1 = dispatch_queue_create("q1",DISPATCH_QUEUE_SERIAL)dispatch_async(q1) { () -> VoidinNSLog("1-%@",NSThread.currentThread()); } let q2 = dispatch_queue_create("q2",DISPATCH_QUEUE_SERIAL)dispatch_async(q2) { () -> VoidinNSLog("2-%@",NSThread.currentThread()); } let q3 = dispatch_queue_create("q3",DISPATCH_QUEUE_SERIAL)dispatch_async(q3) { () -> VoidinNSLog("3-%@",NSThread.currentThread()); } let q4 = dispatch_queue_create("q4",DISPATCH_QUEUE_SERIAL)dispatch_async(q4) { () -> VoidinNSLog("4-%@",NSThread.currentThread()); } let q5 = dispatch_queue_create("q5",DISPATCH_QUEUE_SERIAL)dispatch_async(q5) { () -> VoidinNSLog("5-%@",NSThread.currentThread()); }NSLog("=======>>>asyncSerail<<<========") }
打印结果:
2016-03-23 13:33:21.412 Mutiple[8150:2128078] =======>>>asyncSerail<<<========
2016-03-23 13:33:21.413 Mutiple[8150:2128078] =======>>>asyncSerail<<<========
2016-03-23 13:33:21.414 Mutiple[8150:2128320] 4-(
"{number = 7, name = (null)}"
)
2016-03-23 13:33:21.414 Mutiple[8150:2128308] 1-(
"{number = 3, name = (null)}"
)
2016-03-23 13:33:21.414 Mutiple[8150:2128312] 3-(
"{number = 5, name = (null)}"
)
2016-03-23 13:33:21.414 Mutiple[8150:2128321] 5-(
"{number = 6, name = (null)}"
)
2016-03-23 13:33:21.414 Mutiple[8150:2128311] 2-(
"{number = 4, name = (null)}"
)
小结:
使用GCD实现多线程时:
同步串行和同步并行:都会按照顺序依次执行任务,且不会开启新的线程。
异步串行:会开启新的线程,但是系统默认在同一线程内按照任务顺序依次执行,因为这个时候开了多个线程也要顺序执行任务,开线程只会造成资源浪费
异步并行:开启多个线程,有多个任务同时执行,系统会根据每条线程的情况分配,执行顺序不固定。
在异步串行情况下,可以通过创建多个串行队列,实现异步并行的功能,让多个任务同时进行。
3.3 主队列
The main dispatch queue is a globally available serial queue that executes tasks on the application’s main thread.
主队列是一个全局性的串行队列,用于执行app中主线程的任务,对run loop起作用,将隶属于run loop的事件源与队列任务的执行交织在一起(官方文档翻译过来的,太拗口了。。。)。主队列是一个对于app来说十分重要的同步点,凡是与UI和用户反馈相关的都必须交给主队列完成。这个队列是系统自动创建的,开发者只需要获取队列,并执行操作即可。
获取主线程的方法:
letmainQueue = dispatch_get_main_queue()
最经常用的:
let queue = dispatch_get_global_queue(0,0)dispatch_async(queue,{()-> Void in //在这里做一些耗时的操作 dispatch_async(dispatch_get_main_queue(),{()-> Void in //刷新UI })})
3.4 队列组(dispatch group)
Dispatch groups are a way to block a thread until one or more tasks finish executing.Groups provide a useful synchronization mechanism for code that depends on the completion of other tasks
使用队列组能够实现让一个或多个任务执行完毕之后再执行下一个任务。
Another way to use dispatch groups is as an alternative to thread joins.
使用队列组将多个任务连接在一起。
用队列组可以在特定的场景下实现一些特定的功能,十分有趣:
加入有三个任务:taks1,task2,taks3。task1与task2没有什么特殊关系,task3需要等待task1和task2结束之后才能开始执行。
使用队列组实现任务等待
func dispatchGroup() { let group = dispatch_group_create() let queue1 = dispatch_get_global_queue(0,0) let queue2 = dispatch_get_global_queue(0,0) let queue3 = dispatch_get_global_queue(0,0) dispatch_group_async(group, queue1) { () ->Voidinforiin0..<3{ NSLog("task1 - %d",i) } } dispatch_group_async(group, queue2) { () ->Voidinforiin0..<3{ NSLog("task2 - %d",i) } } dispatch_group_wait(group, DISPATCH_TIME_FOREVER) NSLog("wait completed") dispatch_group_async(group, queue3) { () ->Voidinforiin0..<3{ NSLog("task3 - %d",i) } } }
log输出:
2016-03-24 22:23:25.717 2016-03-24 22:42:42.465 MultipleThradDemo[49112:4109966] task2 - 0
2016-03-24 22:42:42.465 MultipleThradDemo[49112:4109967] task1 - 0
2016-03-24 22:42:42.467 MultipleThradDemo[49112:4109966] task2 - 1
2016-03-24 22:42:42.467 MultipleThradDemo[49112:4109967] task1 - 1
2016-03-24 22:42:42.468 MultipleThradDemo[49112:4109966] task2 - 2
2016-03-24 22:42:42.468 MultipleThradDemo[49112:4109967] task1 - 2
2016-03-24 22:42:42.468 MultipleThradDemo[49112:4109901] wait completed
2016-03-24 22:42:42.469 MultipleThradDemo[49112:4109967] task3 - 0
2016-03-24 22:42:42.469 MultipleThradDemo[49112:4109967] task3 - 1
2016-03-24 22:42:42.469 MultipleThradDemo[49112:4109967] task3 - 2
dispatch_group_wait(group: dispatch_group_t, timeout:dispatch_time_t):括号里面的第一个参数group为等待的队列组,第二个timeout为等待的时间
使用队列组的通知功能实现上述场景:
func groupNotify() { let group = dispatch_group_create() let queue1 = dispatch_get_global_queue(0,0) let queue2 = dispatch_get_global_queue(0,0) let queue3 = dispatch_get_global_queue(0,0) dispatch_group_async(group, queue1) { () ->Voidinforiin0..<3{ NSLog("task1 - %d",i) } } dispatch_group_async(group, queue2) { () ->Voidinforiin0..<3{ NSLog("task2 - %d",i) } } dispatch_group_notify(group, queue3) { () ->VoidinNSLog("task1、 task2 completed")foriin0..<3{ NSLog("task3 - %d",i) } } }
log输出:
2016-03-24 23:05:29.010 MultipleThradDemo[49493:4127151] task2 - 0
2016-03-24 23:05:29.010 MultipleThradDemo[49493:4127148] task1 - 0
2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127148] task1 - 1
2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127151] task2 - 1
2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127148] task1 - 2
2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127151] task2 - 2
2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task1、 task2 completed
2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task3 - 0
2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task3 - 1
2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task3 - 2
3.5 GCD的线程安全
尽管GCD本身就是线程安全的,但是为了更好的使用GCD,apple还是给了几个建议:
Do not call the dispatch_sync function from a task that is executing on the same queue that you pass to your function call
在本队列调用dispatch_sync,再将本队列传入同步方法会造成死锁。
我想apple 的意思应该是这样的:
func deadLock() {//let q = dispatch_get_global_queue(0, 0)let q = dispatch_queue_create("come.multiThread.serialQ", DISPATCH_QUEUE_SERIAL)dispatch_async(q) { () -> VoidinNSLog("1 start-%@",[NSThread.currentThread()]);dispatch_sync(q, { () -> VoidinNSLog("2 start-%@",[NSThread.currentThread()]); })NSLog("3 start-%@",[NSThread.currentThread()]); }NSLog("4 start-%@",[NSThread.currentThread()]); }
但是我发现会不会造成死锁和当前队列是串行还是并行有关。
如果是串行队列,同步执行会阻塞线程,而且串行队列一次只能执行一个任务,q里面等待的任务与同步阻塞的任务是同一个任务,造成死锁。
如果是并行队列,一次能执行多个任务,即使同步阻塞了线程,由于可以多个任务一起执行,q里面没有任务等待,不会造成死锁。
stackoverflow上类似问题的回答:
Usingdispatch_sync()to enqueue a Block to the serial queue on which you're already running is guaranteed to deadlock.Usingdispatch_sync()to enqueue a Block to theconcurrentqueue on which you're already running is quite likely to deadlock.
派发同步任务到在正在执行的串行队列肯定会造成死锁;派发到并行队列也有很大的可能造成死锁。所以上面的例子中,并行队列虽然没有造成死锁,还是有风险的。
note:往主线程派发同步任务也会造成死锁
func mainThreadLock() { let main = dispatch_get_main_queue()NSLog("start-%@",[NSThread.currentThread()]);dispatch_sync(main) { () -> VoidinNSLog("1 -%@",[NSThread.currentThread()]); }NSLog("end-%@",[NSThread.currentThread()]); }
打印输出:
2016-03-25 10:15:46.638 Mutiple[15813:5558093] start-(
"{number = 1, name = main}"
)
同步任务与主线程任务相互等待,造成死锁。
Avoid taking locks from the tasks you submit to a dispatch queue.If you need to synchronize parts of your code, use a serial dispatch queue instead of a lock.
尽量不用自己锁线程,否则得到的结果可能会十分出乎你的意料。使用GCD实现多线程时,apple建议用串行队列替代线程锁。
文/nuclear(简书作者)
原文链接:http://www.jianshu.com/p/0f9f7ed53b48
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
网友评论