源码:https://github.com/baitxaps/Block
一、GCD实现
1>GCD实现需要使用的一些工具:
.用于管理追加的Block的C语言层实现的FIFO队列
.Atomic 函数中实现的用于排他控制的轻量级信号
.用于管理线程的C语言层实现的一些容器
但是还要内核级的实现,通常,应用程序中编写的线程管理用的代码要在系统级(iOS和OS X的核心级)实现
因此,无论编程人员如何努力编写管理线程的代码,在性能方面也不能胜过XNU内核级所实现的GCD。
使用使用GCD要比使用pthreads和NSThread这些一般的多线程编程API更好,并且,如果使用GCD就不必
编写这操作线程反复出现类似的源代码(因定源代码片断),而可以在线程中集中实现处理内容。尽量多使用
GCD或者用Cocoa框架GCD的NSOperationQueue类的API
2>用于实现Dispatch Queue而使用的软件组件
组件名称 提供技术
libdispatch Dispatch Queue
libc(pthreads) pthread_workqueue
XUN内核 workqueue
3>编程人员所使用GCD的API全部为包含有libdispatch库的C函数,Dispatch Queue通过结构体和链表,被
实现为FIFO队列,FIFO队列管理是通过dispatch_async()等函数所追加的Block,Block并不是直接加入FIFO
队列,而是先加入Dispatch Continuation这一dispatch_continuation_t类型结构体中,然后再加入FIFO
队列。Dispatch Continuation用于记忆Block所属的Dispatch Group和其他一些信息(执行上下文)
4>Dispatch Queue可通过dispatch_set_target_queue()设定,可以设定执行该Dispatch Queue处理的
Dispatch Queue为目标。该目标可像串珠子一样,设定多个连接在一起的Dispatch Queue,但是在连接串的最后
必须设定Main Dispatch Queue,或各种优先级的Global Dispatch Queue,或是准备用于Serial Dispatch Queue
的Global Dispatch Queue
5>Global Dispatch Queue的8种优先级:
.High priority
.Default Priority
.Low Priority
.Background Priority
.High Overcommit Priority
.Default Overcommit Priority
.Low Overcommit Priority
.Background Overcommit Priority
附有Overcommit的Global Dispatch Queue使用在Serial Dispatch Queue中,不管系统状态如何,都会强
制生成线程的 Dispatch Queue。
这8种Global Dispatch Queue各使用1个pthread_workqueue,GCD初始化时,使用pthread_workqueue_create_np()
生成pthread_workqueue
pthread_workqueue使用bsdthread_register和workq_open系统调用,在初始化XUN内核的workqueue之后获取workqueue
信息
6>XUN内核的4种workqueue的优先级,与Global Dispatch Queue的4种执行优先级相同
.WORKQUEUE_HIGH_PRIQUEUE
.WORKQUEUE_DEFAULT_PRIQUEUE
.WORKQUEUE_LOW_PRIQUEUE
.WORKQUEUE_BG_PRIQUEUE
7>Dispatch Queue中执行Block过程
当在Global Dispatch Queue中执行Block时,libdispatch从Global Dispatch Queue自身的FIFO队列中取
出Dispatch Continuation,调用pthread_workqueue_additem_np(),将该Global Dispatch Queue自身、符
合优先级的workqueue信息以及为执行Dispatch Continuation的回调函数等传递给参数。
thread_workqueue_additem_np()使用workq_kernreturn系统调用,通知workqueue啬应当执行的项目,根据该
通知,XUN内核基于系统状态判断是否要生成线程,如果是Overcommit优先级的Global Dispatch Queue,workqueue
则始终生成线程。
.该线程虽然与iOS和OS X中通常使用的线程大致相同,但是有一部分pthread API不能使用
.workqueue生成的线程在实现用于workqueue的线程计划表中运行,与一般线程的上下文切不同,这里也隐藏着使用GCD的
原因
.workqueue的线程执行pthread_workqueue(),该函数用libdispatch的回调函数,在回调函数中执行执行加入到
Dispatch Continuatin的Block
.Block执行结束后,进行通知Dispatch Group结束,释放Dispatch Continuation等处理,开始准备执行加入到Dispatch Continuation中的下一个Block
二、常用术语介绍
1.多线程
由于一个CPU一次只能执行一个命令,不能执行某处分开的并列的两个命令,因此通过CPU执行的CPU命令列就
好比一条无分叉的大道,其执行不会出现分歧
一个CPU执行的CPU命令列为一条无分叉路径:线程,这时无分叉路径不只1条,存在有多条时即:多线程。
现在一个物理CPU芯片实际上有64个(64核)CPU,在多线程中,1个CPU核执行多条不同路径上的不同命令。
2.上下文切换
1个CPU核一次能够执行的CPU命令始终为1,OS X和iOS的核心XUN内核在发生操作系统事件时(如每隔一定时间,
唤起系统调用等情况)会切换执行路径。执行中路径的状态,如CPU的寄存器等信息保存到各自路径专用的内存块中,
从切换目标路径专用的内存块中,复原CPU寄存器等信息,继续执行切换路径的CPU命令列:上下文切换
由于使用多线程的程序可以在某个线程和其他线程之间反复多次进行上下文切换,因些看上去就像1个CPU核能够
并列执行多个线程一样,而且在具有多个CPU核的情况下,就是真的提供了多个CPU核并行执行多个线程的技术
3.多线程问题
多线程实际上是一种易发生各种问题的编程技术,比如多个线程更新相同的资源会导致数据的不一致(数据竞争)、
停止等待事件的线程会导致多个线程相互技续等待(死锁)、使用太多线程会消耗大量内存等
4.主线程
应用程序在启动时,通过最先执行的线程。主线程来描绘用户界面、处理触摸屏幕的事件等。如果在该主线程中进行
长时间的处理,就会妨碍主线程的执行(阻塞),在OS和iOS的应用程序中,会妨碍主线程中被称为RunLoop的主循环的
执行,从面导致不能更新用户界面、应用程序的画面长时间停滞等问题
三、常用GCD的API例子
#pragma mark - GCDTest
- (void)GCDTest{
//0.
dispatch_queue_t serialDispatchQueue = dispatch_queue_create("blog.csdn.net/baitxaps", NULL);
//1.
dispatch_queue_t concurrentDispatchQueue = dispatch_queue_create("blog.csdn.com/baitxaps", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentDispatchQueue,^{
NSLog(@"Block on concurrentDispatchQueue");
});
#if !OS_OBJECT_USE_OBJC
//dispatch_release(serialDispatchQueue);
dispatch_release(concurrentDispatchQueue);
#endif
//2.各种Dispatch Queue获取方法
/*
对于 Main Dispatch Queue和Global Dispatch Queue执行dispatch_retain、dispatch_release函数不会引用作何变化,
也不会有任何问题
*/
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();//main Dispatch Queue
dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);//最高优先级
dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//默认优先级
dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);//默认优先级
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);//后台优先级
//3.默认优先级的Global Dispatch Queue中执行Block
dispatch_async(globalDispatchQueueDefault, ^{
// 并行执行的处理
//...
dispatch_async(mainDispatchQueue, ^{
//只能在主线程中执行的处理
//...
});
});
//4.指定变更执行优先级(在后台执行动作处理的Serial Dispatch Queue的生成方法)
dispatch_set_target_queue(serialDispatchQueue, globalDispatchQueueBackground);
//5.在指定时间后执行处理的情况,用dispatch_after
dispatch_time_t time =dispatch_time(DISPATCH_TIME_NOW, 3ull *NSEC_PER_MSEC);
dispatch_after(time, mainDispatchQueue, ^{
NSLog(@"waited at least 3 seconds.");
});
//6.dispatch_walltime()
dispatch_time_t seconds = getDispatchTimeByDate([NSDate date]);
NSLog(@"second = %llu",seconds);
//7.Dispatch Group
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, globalDispatchQueueDefault, ^{ NSLog(@"blk0");});
dispatch_group_async(group, globalDispatchQueueDefault, ^{ NSLog(@"blk1");});
dispatch_group_async(group, globalDispatchQueueDefault, ^{ NSLog(@"blk2");});
dispatch_group_notify(group, mainDispatchQueue, ^{ NSLog(@"done");});
#if !OS_OBJECT_USE_OBJC
dispatch_release(group);
#endif
//7.dispatch_group_wait()
dispatch_group_t group_wait = dispatch_group_create();
dispatch_group_async(group_wait, globalDispatchQueueDefault, ^{ NSLog(@"blk0");});
dispatch_group_async(group_wait, globalDispatchQueueDefault, ^{ NSLog(@"blk1");});
dispatch_group_async(group_wait, globalDispatchQueueDefault, ^{ NSLog(@"blk2");});
dispatch_group_wait(group_wait, DISPATCH_TIME_FOREVER);
#if !OS_OBJECT_USE_OBJC
dispatch_release(group_wait);
#endif
//8.
time = dispatch_time(DISPATCH_TIME_NOW,1ull *NSEC_PER_SEC);
dispatch_group_t group_result = dispatch_group_create();
long result = dispatch_group_wait(group_result, time);
// long result = dispatch_group_wait(group_result, DISPATCH_TIME_NOW);
if (result == 0) {
//属于Dispatch Group的全部内容处理执行结束
}else{
//属于Dispatch Group的某一个处理还在执行中
}
//9.dispatch_barrier_async()
dispatch_async(concurrentDispatchQueue, ^{ NSLog(@"blk0 for reading");});
dispatch_async(concurrentDispatchQueue, ^{ NSLog(@"blk1 for reading");});
dispatch_async(concurrentDispatchQueue, ^{ NSLog(@"blk2 for reading");});
dispatch_barrier_async(concurrentDispatchQueue, ^{ NSLog(@"blk3 for writing");});
dispatch_async(concurrentDispatchQueue, ^{ NSLog(@"blk4 for reading");});
dispatch_async(concurrentDispatchQueue, ^{ NSLog(@"blk5 f