1、什么是GCD?编程
如下是摘自苹果的官方说明。安全
Grand Central Dispatch(GCD)是异步执行任务的技术之一。通常将应用程序中记述的线程管理用的代码在系统级中实现。开发者只须要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。多线程
2、GCD实现之Dispatch Queue并发
GCD的API所有包含在libdispatch库中的C语言函数。Dispatch Queue经过结构体和链表,被实现为FIFO队列。FIFO队列管理是经过dispatch_async等函数所追加的Block。异步
Block并非直接加入FIFO队列,而是先加入Dispatch Continuation这一dispatch_continution_t类结构体中,而后再加入FIFO队列。该Dispatch Continuation用于记忆Block所属的Dispatch Group和其余一些信息,至关于通常常说的执行上下文。async
Dispatch Queue可经过dispatch_set_target_queue函数设定,能够设定执行该Dispatch Queue处理的Dispatch Queue为目标。该目标可像串珠子同样,设定多个链接在一块儿的Dispatch Queue。可是在链接串的最后必须设定为Main Dispatch Queue,或各类优先级的Global Dispatch Queue,或是准备用于Serial Dispatch Queue的各类优先级的 Global Dispatch Queue.函数
Global Dispatch Queue有以下8种。spa
优先级中附有Overcommit的Global Dispatch Queue使用在Serial Dispatch Queue中。如Overcommit这个名称所示,无论系统状态如何,都会强制生成线程的Dispatch Queue。线程
这8种Global Dispatch Queue各使用1个pthread_workqueue。GCD初始化时,使用pthread_workqueue_create_np函数生成pthread_workqueue。 调试
pthread_workqueue包含在Libc提供的pthreads API中。其使用bsdthread_register和workq_open系统调用,在初始化XNU内核的workqueue以后获取workqueue信息。
XNU内核持有4中workqueue。
以上为4种执行优先级的workqueue。该执行优先级与Global Dispatch Queue的4种执行优先级相同。
Dispatch Queue中执行Block的过程。
当在Global Dispatch Queue中执行Block时,libdispatch从Global Dispatch Queue自身的FIFO队列中取出Dispatch Continuation,调用pthread_workqueue_additem_np函数。将该Global Dispatch Queue自身、符合其优先级的workqueue信息以及为执行Dispatch Continuation的回调函数等传递给参数。
pthread_workqueue_additem_np函数使用workq_kernreturn系统调用,通知workqueue增长应当执行的项目。根据该通知,XNU内核基于系统状态判断是否须要生成线程。若是是Overcommit优先级的Global Dispatch Queue,workqueue则始终生成线程。
workqueue的线程执行pthread_workqueue函数,该函数调用libdispatch的回调函数。在该回调函数中执行加入到Dispatch Continuation的Block。
Block执行结束后,进行通知Dispatch Group结束、释放Dispatch Continuation等处理,开始准备执行加入到Global Dispatch Queue中的下一个Block。
以上就是Dispatch Queue执行的大概过程。
3、线程和队列
线程是代码执行的路径,队列则是用于保存以及管理任务的,线程负责去队列中取任务进行执行。
1、队列
是管理线程的,至关于线程池,能管理线程何时执行。
队列分为串行队列和并行队列等
串行队列:队列中的任务按顺序执行
并行队列:队列中的任务会并发执行。任务执行完毕了,不必定出队列。只有前面的任务执行完了,才会出队列。
串行队列:队列中的任务只会顺序执行,多个串行队列可并行执行
dispatch_queue_t q = dispatch_queue_create(“xxx”,DISPATCH_QUEUE_SERIAL);
并行队列:队列中的任务会并发执行
dispatch_queue_t q = dispatch_queue_create(“xxx”, DISPATCH_QUEUE_CONCURRENT);
全局队列:与并行队列相似,但调试时,没法确认操做所在队列
dispatch_queue_t q = dispatch_get_global_queue(dispatch_queue_priority_default, 0);
主队列:每个程序对应惟一一个主队列;在多线程开发中,使用主队列更新UI
dispatch_queue_t q = dispatch_get_main_queue();
二、同步和异步
dispatch_async (异步操做函数),就是将指定的Block“非同步”地追加到指定的队列(queue)中。dispatch_async函数不作任何等待。会新开线程
dispatch_sync( 同步操做函数),就是将指定的Block“同步”地追加到指定的队列(queue)中。在追加Block结束以前,dispatch_sync函数会一直等待;不会新开线程
三、队列和操做的组合
串行队列同步操做:同步操做不会新开线程、操做顺序执行
串行队列异步操做:异步操做新开一个子线程、操做顺序执行,“最安全的选择”
并行队列同步操做:同步操做不会新开线程、操做顺序执行
并行队列异步操做:异步操做会新开多个线程(有多少任务,就开n个线程执行)、操做无序执行;队列前若是有其余任务,会等待前面的任务完成以后再执行;场景:既不影响主线程,又不须要顺序执行的操做!
全局队列异步操做:异步操做会新建多个线程、操做无序执行,队列前若是有其余任务,会等待前面的任务完成以后再执行
全局队列同步操做:同步操做不会新建线程、操做顺序执行
主队列异步操做:异步操做都在主线程上顺序执行的,不存在异步的概念
主队列同步操做:会死锁
四、会引发死锁的2种状况
一、在主线程中运用主队列同步。
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"hello");
});
}
同步对于任务是马上执行的,那么当把任务放进主队列时,它就会立马执行,只有执行完这个任务,viewDidLoad才会继续向下执行。
而viewDidLoad和任务都是在主队列上的,因为队列的先进先出原则,任务又需等待viewDidLoad执行完毕后才能继续执行,viewDidLoad和这个任务就造成了相互循环等待,就形成了死锁。
想避免这种死锁,能够将同步改为异步dispatch_async,或者将dispatch_get_main_queue换成其余串行或并行队列,均可以解决。
二、在串行队列中同步的向这个串行队列追加Block
dispatch_queue_t serialQueue = dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
dispatch_sync(serialQueue, ^{
NSLog(@"hello");
});
});
想避免这种死锁,能够将同步改为异步dispatch_async,或者将串行队列换为并行队列,均可以解决。
以上部份内容参考自《Objective-C高级编程》一书