GCD,Grand Central Dispatch,iOS中常用的多线程技术,GCD提供C风格的API,相对NSOperationQueue以及NSThread,它更加的简单易用且功能强大.
注意:现在dispatc_group_t,dispatch_queue_t, dispatch_semaphore_t等已经被ARC管理,无需要手动release.
队列 dispatch_queue_t
GCD提供两种队列Serial Dispatch Queue(串行队列),Concurrent Dispatch Queue(并发队列). 使用APIdispatch_queue_create
创建.
dispatch_queue_t requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);
第一个参数为队列的名字, 也可以写为NULL,不过为了调试推荐指定对列名字.
第二个参数为DISPATCH_QUEUE_CONCURRENT
或DISPATCH_QUEUE_SERIAL
,用于指定队列的类型.
dispatch_async(requestHeaderModificationQueue, ^{
.........
});
dispatch_release(requestHeaderModificationQueue);
GCD的队列,必须由程序员手动进行引用计数的管理,当队列需要释放的时候,要手动的调用dispatch_release
. 上面的代码不会立即释放队列,因为block强引用了requestHeaderModificationQueue,会等block中的任务执行完毕才会释放队列.
同时GCD提供dispatch_get_main_queue()
和dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
可以便捷的获取主线程和后台线程.
向队列中追加任务 dispatch_async和dispatch_sync
dispatch_async(requestHeaderModificationQueue, ^{
.........
});
dispatch_sync(requestHeaderModificationQueue, ^{
.........
});
使用dispatch_async和dispatch_sync向队列中追加任务.
dispatch_async
.异步执行,并不会阻塞当前的线程,而是立即向下执行.
dispatch_sync
同步执行,会阻塞当前线程,等待block中的任务执行完毕,程序才会继续向下执行. 所以要避免在主线程中使用dispatch_sync
disaptch_after
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
...
});
上面的代码意思为在5秒后执行block中的任务.
dispatch_after 函数接受三个参数
1.第一个参数是指定时间,用的是 dispatch_time_t 类型的值. 使用dispatch_time 或者 dispatch_walltime函数生成.
dispatch_time函数能够获取从第一个参数dispatch_time_t类型的值,到第二个参数指定的毫秒单位时间后的时间. 如上例,第二个参数为5 * NSEC_PER_SEC
毫秒也就是5秒.
2.第二个参数指定要追加任务的队列.
dispatch_group
dispatch_group_t group = dispatch_group_create()
使用函数dispatch_group_create创建.
dispatch_group同样需要程序员手动的管理引用计数. 同dispatch_queue.
dispatch_group同样有同步执行和异步执行两个函数:dispatch_group_async
和dispatch_group_sync
.
dispatch_group_async(<#dispatch_group_t _Nonnull group#>, <#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)
比起dispatch_queue的对出一个参数,指定该block属于指定的dispatch_group_t.
dispatch_group_notify
如果存在多个任务或者多个队列,想要在所有的任务执行完成后,执行指定的操作,可以使用dispatch_group_notify.
dispatch_group_notify会监听指定的group,在所有任务执行完成后,将指定的任务加入指定的队列中.
dispatch_queue_t queue = dispatch_queue_create("xxx.aaa.ccc", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
// ...
});
dispatch_group_async(group, queue, ^{
// ...
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
});
dispatch_group_notify
dispatch_group_wait
long result = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
if (result == 0) {
NSLog(@"group全部执行");
}else{
NSLog(@"group并没有全部执行");
}
一般来说,线程有三个状态.
- 运行,running,此刻线程正在运行
- 等待,waiting,此刻线程正在等待某一时间发生,无法执行.
-
就绪,ready,此刻线程可以立即执行,但是cpu已经被占用.
操作系统按照优先级或者平均分配给每个线程执行时间. 当该线程分配的时间片未用完之前,线程开始等待某事件, 它就会等待状态. 每当一个线程离开运行状态时,操作系统会选择一个其他的就绪线程立即执行.
dispatch_group_wait函数会使当前线程处于等待状态,并不返回.直到指定的group中的任务全部完成或者指定的时间到达后. 如上例子,group任务全部完成或者5秒之后,函数返回,如果group中的任务全部完成,将会返回0 ,否则返回非0.
当时间指定为DISPATCH_TIME_FOREVER
意为永久等待,直到group中的任务全部完成.
dispatch_barrier_sync
dispatch_barrier_sync(queue, ^{
...
});
dispatch_barrier_sync
可以理解为栅栏函数,在该block加入队列前加入queue的任务全部执行完之后再去执行该任务. 然后才会执行后面加入的任务. 像一个栅栏一样,把前后的任务隔离开. 可以用来在并发队列中控制任务顺序.
dispatch_suspend和dispatch_resume
队列的挂起以及恢复.
dispatch_semaphore_t
在使用并发队列执行多个任务时,任务的完成时间以及顺序并不能控制,可以使用dispatch_barrier_sync
和dispatch_group_notify
. 这里还有另外一个方法,那就是dispatch_semaphore_t
Dispatch Semaphore 是持有计数的信号,该计数是多线程编程中的计数类型的信号. 在Dispatch Semaphore中,计数为0时等待,计数为大于或者等于1时信号减去1而不对等待.
dispatch_semaphore_t semphore = dispatch_semaphore_create(1);
result = dispatch_semaphore_wait(semphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(semphore);
dispatch_release(semphore);
以以上代码为例
第一句,创建一个Dispatch Semaphore并且制定信号量为1
第二句,永久等待Dispatch Semaphore的信号量大于0,然后返回.代码乡下执行.
第三句,执行完任务后,将Dispatch Semaphore的计数值加1
第四句,如果该Dispatch Semaphore结束使用,那么手动释放.
dispatch_once_t
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
<#code to be executed once#>
});
dispatch_once函数保证应用程序运行中,即使在多线层环境下,也只执行一次指定的任务.常常用来被使用生成单例.