苹果提供的基于 C 的一组 API,用于多线程编程
一、队列
并行队列:任务以FIFO顺序出列,但可以同时运行并且可以按任何顺序完成。
串行队列:任务以FIFO顺序一次执行一个。
1、创建自定义队列
dispatch_queue_t queue = dispatch_queue_create(“队列标识符”, NULL);
第一个参数是标识符,可以为空
第二个参数用来表示创建的队列是串行的还是并行的
传入 DISPATCH_QUEUE_SERIAL 或 NULL 表示创建串行队列。
传入 DISPATCH_QUEUE_CONCURRENT 表示创建并行队列。
2、获取主队列(串行队列)
dispatch_queue_t queue = dispatch_get_main_queue();
3、获取全局队列(并行队列)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
第一个参数标识任务优先级,高、中、低依次为
DISPATCH_QUEUE_PRIORITY_HIGH、
DISPATCH_QUEUE_PRIORITY_DEFAULT、
DISPATCH_QUEUE_PRIORITY_LOW。
一般默认为 DISPATCH_QUEUE_PRIORITY_DEFAULT。
第二参数作为保留字段备用,一般为 0。
注意:由于主队列和全局队列是系统控制的,所以我们无法对其进行 dispatch_resume(queue) 继续 和 dispatch_suspend(queue) 中断
二、线程
同步线程:不具备开辟新线程能力;必须任务执行完成之后才会返回,等待;
dispatch_sync(queue, ^{
});
异步线程:具备开辟新线程的能力;任务加入队列之后立即返回,不等待;
dispatch_async(queue, ^{
});
三、死锁
1、主线程中同步的添加新任务至主队列
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"new task");
});
2、串行队列 queue 中的任务 A 同步地添加任务 B 至队列 queue
dispatch_queue_t queue = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"A task");
dispatch_sync(queue, ^{
NSLog(@"B task");
});
});
四、任务组
通过添加任务到任务组可以获取到任务组完成事件
添加任务方式一:
dispatch_group_async(group, queue, ^{
});
dispatch_group_sync(group, queue, ^{
});
添加任务方式二:
task 开始时调用 dispatch_group_enter(group)
task 结束时调用 dispatch_group_leave(group)
如果 dispatch_group_enter 比 dispatch_group_leave 多,则wait函数等待的线程不会被唤醒和注册 notify 的回调 block 不会执行;
如果 dispatch_group_leave比dispatch_group_enter多,则会引起"Unbalanced call to dispatch_group_leave()"的崩溃。
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
当前线程会等待任务组中的任务全部完成后,才会继续执行任务(阻塞当前线程)
dispatch_group_notify(group, queue, ^{
});
任务组中的任务全部完成后,添加任务至指定队列并执行
五、常用 GCD 函数
1、延迟执行函数
DISPATCH_TIME_NOW
DISPATCH_TIME_FOREVER
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC))
NSEC_PER_SEC 纳秒/秒 1, 000, 000, 000
NSEC_PER_MSEC 纳秒/毫秒 1, 000, 000
NSEC_PER_USEC 纳秒/微秒 1, 000
可以理解为系统以纳秒为单位。
dispatch_after(time, queue, ^{
})
2、单次任务
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
});
3、异步执行特定次数任务;执行之后才会返回;
dispatch_apply(count, queue, ^(size_t index) {
})