iOS开发中使用最多的是GCD, 基础内容参考官方文档. 开发中我们有几个概念需要了解:
最重要的两个概念: 任务(task)
和 队列(queue)
.
在学习GCD之前, 最重要的是理解 任务
和 队列
.
GCD Queue类型
queue
: 是GCD的调度核心, 所有的任务都是同步
或异步
加入到queue
中, 多个任务被添加到queue以后, 任务的执行顺序, 由queue
类型决定.
queue
有以下类型:
serial queue: 串行队列.追加处理必须按照顺序一个个执行.并且 1.等待现在执行中处理结束, 2.使用一个线程
concurrent queue: 并行队列.可以并行执行多个追加处理.并且 1.不等待现在执行中处理结束, 2.使用多个线程
main queue: 主队列. 是一个全局唯一的 serial queue, 它只会将任务调度到main thread中执行.
多个serial dispatch queue 可以并行执行.
GCD 同步与异步执行
异步执行与同步执行:
- 异步执行(调度): 就是将指定的block,
非同步
地追加到指定的Dispatch Queue中. dispatch_async函数不做任何等待. - 同步执行(调度): 就是将指定的block,
同步
地追加到指定的Dispatch Queue中. dispatch_async函数会一直等待处理执行结束.
等待
意味着当前线程会停止.
同步与异步调用:
dispatch_async
与dispatch_sync
两者区别是:
- 是否会创建一个新thread去执行task
- 调用方法是否会先返回
并行队列与串行队列的特点(都是在异步(dispatch_async)函数下有效):
- 并行队列: 队列中的任务可以同时执行.会开启多个线程, 让任务同时执行.
- 串行队列: 队列中的任务必须顺序执行.每次只执行一个任务,一个任务执行完成以后, 接着执行下一个任务.
注意:
- 并行队列的并发功能只有在异步(
dispatch_async
)函数下才有效,如果在同步(dispatch_sync
)函数下, 执行只在当前线程顺序执行.- 串行队列异步执行(
dispatch_async
)执行, 会开启一个新线程, 任务顺序执行.同步(dispatch_sync
)函数下执行, 可能造成死锁.
如果组合有以下特点:
具体的调用方式与队列类型组合实例
1. 异步调用 + 并行队列
/*
主线程 + 异步执行 + 并行队列
1. ---start---, thread: {number = 1, name = main}
2. ---end---, thread: {number = 1, name = main}
3. 任务3---thread:{number = 3, name = (null)}---queue:
4. 任务1---thread:{number = 4, name = (null)}---queue:
5. 任务2---thread:{number = 5, name = (null)}---queue:
*/
- (void)asyncConcurrent1{
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("my queue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"---start---, thread: %@", [NSThread currentThread]);
//使用异步函数调用会创建新线程, 并行队列会创建多个线程.
dispatch_async(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_async(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_async(queue, ^{
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}
/*
子线程 + 异步执行 + 并行队列
1. ---start---, thread: {number = 3, name = (null)}
2. ---end---, thread: {number = 3, name = (null)}
3. 任务1---thread:{number = 4, name = (null)}---queue:
4. 任务2---thread:{number = 5, name = (null)}---queue:
5. 任务3---thread:{number = 6, name = (null)}---queue:
*/
- (void)asyncConcurrent2 {
dispatch_queue_t queue = dispatch_queue_create("my queue", DISPATCH_QUEUE_CONCURRENT);
[NSThread detachNewThreadWithBlock:^{
NSLog(@"---start---, thread: %@", [NSThread currentThread]);
// 异步调用, 会为queue开启线程, concurrent, 会开启多个线程
dispatch_async(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_async(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_async(queue, ^{
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}];
}
结果解释:
- 先打印
start
, 然后打印end
. async调用不会阻塞当前线程, 会跳过task, 继续向后执行. - async调用, 会创建线程. 这里创建了3个线程.
- 执行 task1, task2, task3, 三者都在不同线程中执行, 并且是并行执行.
2. 异步执行 + 串行队列
/*
主线程 + 异步执行 + 串行队列
1. ---start---, thread: {number = 1, name = main}
2. ---end---, thread: {number = 1, name = main}
3. 任务1---thread:{number = 3, name = (null)}---queue:
4. 任务2---thread:{number = 3, name = (null)}---queue:
5. 任务3---thread:{number = 3, name = (null)}---queue:
*/
- (void)asyncSerial1{
//创建一个串行队列
dispatch_queue_t queue = dispatch_queue_create("my queue2", DISPATCH_QUEUE_SERIAL);
NSLog(@"---start---, thread: %@", [NSThread currentThread]);
// 异步调用, 会开启新线程,串行队列只会开启一个线程
dispatch_async(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_async(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_async(queue, ^{
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}
/*
子线程 + 异步执行 + 串行队列
1. ---start---, thread: {number = 3, name = (null)}
2. ---end---, thread: {number = 3, name = (null)}
3. 任务1---thread:{number = 4, name = (null)}---queue:
4. 任务2---thread:{number = 4, name = (null)}---queue:
5. 任务3---thread:{number = 4, name = (null)}---queue:
*/
- (void)asyncSerial2{
//创建一个串行队列
dispatch_queue_t queue = dispatch_queue_create("my queue2", DISPATCH_QUEUE_SERIAL);
[NSThread detachNewThreadWithBlock:^{
NSLog(@"---start---, thread: %@", [NSThread currentThread]);
// 异步调用, 因此会为这个queue开启新线程, serial只会开启一个线程
dispatch_async(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_async(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_async(queue, ^{
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}];
}
结果解释:
- 先打印
start
, 然后打印end
. async调用不会阻塞当前线程, 会跳过task, 继续向后执行. - 使用async, 异步调用到 serial queue, 会创建一个线程.
- 使用串行队列, 队列中的 task 按照添加入的顺序, 顺序执行1,2,3.
3. 同步执行 + 并行队列
/*
主线程 + 同步执行 + 并行队列
1. ---start---, thread: {number = 1, name = main}
2. 任务1---thread:{number = 1, name = main}---queue:
3. 任务2---thread:{number = 1, name = main}---queue:
4. 任务3---thread:{number = 1, name = main}---queue:
5. ---end---, thread: {number = 1, name = main}
*/
- (void)syncConcurrent1{
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("my queue2.1", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"---start---, thread: %@", [NSThread currentThread]);
dispatch_sync(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}
/*
子线程 + 同步执行 + 并行队列
1. ---start---, thread:{number = 3, name = (null)}
2. 任务1---thread:{number = 3, name = (null)}---queue:
3. 任务2---thread:{number = 3, name = (null)}---queue:
4. 任务3---thread:{number = 3, name = (null)}---queue:
5. ---end---, thread: {number = 3, name = (null)}
*/
- (void)syncConcurrent2{
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("my queue2.2", DISPATCH_QUEUE_CONCURRENT);
[NSThread detachNewThreadWithBlock:^{
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
//使用同步函数封装三个任务
dispatch_sync(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}];
}
结果解释:
- 同步执行(sync), 不会创建新线程, 会在调用dispatch_sync函数的当前线程运行task.
- 并行队列, 并发功能在同步执行中无效, 所有task按照添加顺序一个个顺序执行.
- 整个顺序是在当前线程执行: start -> task1 -> task2 -> task3 -> end
4. 同步执行 + 串行队列
/*
主线程 + 同步执行 + 串行队列
1. ---start---, thread:{number = 1, name = main}
2. 任务1---thread:{number = 1, name = main}---queue:
3. 任务2---thread:{number = 1, name = main}---queue:
4. 任务3---thread:{number = 1, name = main}---queue:
5. ---end---, thread: {number = 1, name = main}
*/
- (void)syncSerial1{
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("my queue3.1", DISPATCH_QUEUE_SERIAL);
// 创建一个子线程, 然后去 同步执行+ 并行队列
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
//使用同步函数封装三个任务
dispatch_sync(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}
/*
子线程 + 同步执行 + 串行队列
1. ---start---, thread:{number = 3, name = (null)}
2. 任务1---thread:{number = 3, name = (null)}---queue:
3. 任务2---thread:{number = 3, name = (null)}---queue:
4. 任务3---thread:{number = 3, name = (null)}---queue:
5. ---end---, thread: {number = 3, name = (null)}
*/
- (void)syncSerial2{
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("my queue3.1", DISPATCH_QUEUE_SERIAL);
// 创建一个子线程, 然后去 同步执行+ 并行队列
[NSThread detachNewThreadWithBlock:^{
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
//使用同步函数封装三个任务
dispatch_sync(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}];
}
结果解释:
- 同步执行(sync), 不会创建新线程, 会在调用dispatch_sync函数的当前线程(主线程或者子线程)运行task.
- 串行队列, 所有task按照添加顺序一个个顺序执行.
- 整个顺序是在当前线程执行: start -> task1 -> task2 -> task3 -> end
5. 同步执行 + mainQueue
/*
主线程 + 同步执行 + mainQueue
结果死锁
*/
- (void)syncInMainQueue1{
//创建一个并行队列
dispatch_queue_t queue = dispatch_get_main_queue();
// 创建一个子线程, 然后去 同步执行+ 并行队列
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
//使用同步函数封装三个任务
dispatch_sync(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}
/*
子线程中 + 同步 + mainQueue
1. ---start---, thread:{number = 3, name = (null)}
2. 任务1---thread:{number = 1, name = main}---queue:
3. 任务2---thread:{number = 1, name = main}---queue:
4. 任务3---thread:{number = 1, name = main}---queue:
5. ---end---, thread: {number = 3, name = (null)}
*/
- (void)syncInMainQueue2{
//创建一个并行队列
[NSThread detachNewThreadWithBlock:^{
//创建一个并行队列
dispatch_queue_t queue = dispatch_get_main_queue();
// 创建一个子线程, 然后去 同步执行+ 并行队列
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
//使用同步函数封装三个任务
dispatch_sync(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_sync(queue, ^{
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}];
}
结果解释:
- 主线程中同步会等到block执行完成才返回,sync在dispatch_get_main_queue() 队列中, 它是串行队列,sync是后加入的,前一个是主线程,所以 sync 想执行 block 必须等待主线程执行完成,主线程等待 sync 返回,去执行后续内容。因此, sync 等待mainThread 执行完成, mianThread 等待sync 函数返回, 两者互相等待, 造成死锁.
- 在子线程中调用时, 由于当前线程是子线程, 因此sync只会阻塞子线程, 待task在mainThread中执行完成以后,执行后面的内容.
6. 同步异步的嵌套情况
/**
同步嵌套 + 串行队列的死锁
1. ---start---, thread:{number = 1, name = main}
2. 任务1---thread:{number = 1, name = main}---queue:
3. 死锁!!!!!!!!!!!!!!(不会执行 end)
*/
-(void)deadLockTestSerialQueue{
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
//使用同步函数封装三个任务
dispatch_sync(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
dispatch_sync(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}
结果解释:
- 因为串行队列中线程是有执行顺序的,需要task1的同步任务执行完毕,才会执行下面开启的task2同步任务。而task1同步任务还没执行完,要到下面的大括号才算执行完毕,而task2同步任务已经在抢占资源了,就会发生死锁。
简单理解, 串行队列中, 有两个同步任务嵌套, 会导致第二个同步线程运行死锁.
/**
同步嵌套 + 并行队列 --> 正常执行
1. ---start---, thread:{number = 1, name = main}
2. 任务1---thread:{number = 1, name = main}---queue:
3. 任务2---thread:{number = 1, name = main}---queue:
4. sleep 5s---thread:{number = 1, name = main}---queue:
5. 任务3---thread:{number = 1, name = main}---queue:
6. sleep 5s---thread:{number = 1, name = main}---queue:
7. ---end---, thread: {number = 1, name = main}
*/
-(void)deadLockTestConcurrentQueue{
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
// 创建一个子线程, 然后去 同步执行+ 并行队列
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
//使用同步函数封装三个任务
dispatch_sync(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
dispatch_sync(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
[NSThread sleepForTimeInterval:5];
NSLog(@"sleep 5s---thread:%@---queue:%@ ", [NSThread currentThread], queue);
});
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
[NSThread sleepForTimeInterval:5];
NSLog(@"sleep 5s---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}
结果解释:
- 同步调用, 会在当前线程中运行(不会创建子线程), 并且等待当前dispatch_sync函数调用返回. 使用并行队列, task1/task3 和 task2 的执行没有顺序, 因此会立即执行task2, 然后睡眠5s, 然后打印task3...最后执行end.
同步嵌套, 如果使用并行队列, 会正常运行, 不会造成死锁.
/**
异步调用嵌套同步调用 + 串行队列 == 死锁 (同 主线程, 用同步mainQueue)
1. ---start---, thread:{number = 1, name = main}
2. ---end---, thread: {number = 1, name = main}
3. 任务1---thread:{number = 3, name = (null)}---queue:
4. 死锁!!!!!!!!!!!!!!
*/
-(void)deadLockTestSerialQueue2{
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
// 创建一个子线程, 然后去 同步执行+ 并行队列
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
//使用同步函数封装三个任务
dispatch_async(queue, ^{
NSLog(@"任务1---thread:%@---queue:%@", [NSThread currentThread], queue);
dispatch_sync(queue, ^{
NSLog(@"任务2---thread:%@---queue:%@", [NSThread currentThread], queue);
[NSThread sleepForTimeInterval:5];
NSLog(@"sleep 5s---thread:%@---queue:%@ ", [NSThread currentThread], queue);
});
NSLog(@"任务3---thread:%@---queue:%@", [NSThread currentThread], queue);
[NSThread sleepForTimeInterval:5];
NSLog(@"sleep 5s---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end---, thread: %@", [NSThread currentThread]);
}
结果解释:
- 由于queue是串行队列, 在串行队列中同步串行队列, 死锁
特别注意队列的类型,
串行队列同步调用
很容易造成死锁
GCD中Target Queue作用
前面我们了解到, 通过 dispatch_sync
可以同步执行重要的代码. 本节学习用target queue
可以帮助我们将多个queue之间的block执行保持串行执行.
1. 使用dispatch_set_target_queue更改Dispatch Queue的执行优先级
dispatch_queue_create
函数生成的dispatch queue不管是serial dispatch Queue还是Concurrent Dispatch Queue, 执行的优先级都与默认优先级的Global Dispatch queue相同,如果需要变更生成的Dispatch Queue的执行优先级则需要使用dispatch_set_target_queue函数.
- (void)testTeagerQueue1 {
dispatch_queue_t serialQueue = dispatch_queue_create("com.oukavip.www",NULL);
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);
dispatch_set_target_queue(serialQueue, globalQueue);
// 第一个参数为要设置优先级的queue,第二个参数是参照物,既将第一个queue的优先级和第二个queue的优先级设置一样。
}
2.使用dispatch_set_target_queue修改用户队列的目标队列,使多个serial queue在目标queue上一次只有一个执行.
/**
理论上, 多个 serialQueue queue1,queue2,queue3, dispatch_async到一个并行队列中, 应该是分别在三个thread中并行执行的.但是这里设置 target_queue以后, 三个线程都在number=3的同一个线程中执行.
多个serial queue在多个线程并行执行 ---> 多个serial queue在同一个线程中串行执行
1. ---start---, thread:{number = 1, name = main}
2. ---end---, thread:{number = 1, name = main}
3. 任务1 in:---thread:{number = 3, name = (null)}---queue:
4. 任务1 out:---thread:{number = 3, name = (null)}---queue:
5. 任务2 in:---thread:{number = 3, name = (null)}---queue:
6. 任务2 out:---thread:{number = 3, name = (null)}---queue:
7. 任务3 in:---thread:{number = 3, name = (null)}---queue:
8. 任务3 out:---thread:{number = 3, name = (null)}---queue:
使用场景: 一般都是把一个任务放到一个串行的queue中,如果这个任务被拆分了,被放置到多个串行的queue中,但实际还是需要这个任务同步执行,那么就会有问题,因为多个串行queue之间是并行的。这时候dispatch_set_target_queue将起到作用。(实际上这种类型的需求使用NSOperation更好)
*/
-(void)testTargetQueue1 {
// 目标队列是 串行队列
dispatch_queue_t targetQueue = dispatch_queue_create("test.target.queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue1 = dispatch_queue_create("test.1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 = dispatch_queue_create("test.2", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue3 = dispatch_queue_create("test.3", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(queue1, targetQueue);
dispatch_set_target_queue(queue2, targetQueue);
dispatch_set_target_queue(queue3, targetQueue);
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
dispatch_async(queue1, ^{
NSLog(@"任务1 in:---thread:%@---queue:%@", [NSThread currentThread], queue1);
[NSThread sleepForTimeInterval:3.f];
NSLog(@"任务1 out:---thread:%@---queue:%@", [NSThread currentThread], queue1);
});
dispatch_async(queue2, ^{
NSLog(@"任务2 in:---thread:%@---queue:%@", [NSThread currentThread], queue2);
[NSThread sleepForTimeInterval:3.f];
NSLog(@"任务2 out:---thread:%@---queue:%@", [NSThread currentThread], queue2);
});
dispatch_async(queue3, ^{
NSLog(@"任务3 in:---thread:%@---queue:%@", [NSThread currentThread], queue3);
[NSThread sleepForTimeInterval:3.f];
NSLog(@"任务3 out:---thread:%@---queue:%@", [NSThread currentThread], queue3);
});
NSLog(@"---end---, thread:%@", [NSThread currentThread]);
}
/**
1. ---start---, thread:{number = 1, name = main}
2. ---end---, thread:{number = 1, name = main}
3. 任务1 in:---thread:{number = 3, name = (null)}---queue:
4. 任务1 in:---thread:{number = 3, name = (null)}---queue:
5. 任务2 in:---thread:{number = 3, name = (null)}---queue:
6. 任务2 in:---thread:{number = 3, name = (null)}---queue:
7. 任务3 in:---thread:{number = 3, name = (null)}---queue:
8. 任务3 in:---thread:{number = 3, name = (null)}---queue:
queue1是并行队列, queue2是串行队列.在都设置 串行队列targetQueue作为目标队列以后. 所有的异步调用dispatch_async到queue1, queue2的block, 都好像dispatch_async到targetQueue中执行一样.
*/
- (void)testTargetQueue2 {
// target-queue是 串行队列
dispatch_queue_t targetQueue = dispatch_queue_create("targetQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);//串行队列
dispatch_queue_t queue2 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);//并发队列
//设置参考, targetQueue是参考队列.
dispatch_set_target_queue(queue1, targetQueue);
dispatch_set_target_queue(queue2, targetQueue);
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
// 虽然是异步调用但是是顺序执行.因为targetQueue是serial, 创建队列的层次体系
dispatch_async(queue1, ^{
NSLog(@"任务1 in:---thread:%@---queue:%@", [NSThread currentThread], queue1);
[NSThread sleepForTimeInterval:2.f];
NSLog(@"任务1 in:---thread:%@---queue:%@", [NSThread currentThread], queue1);
});
dispatch_async(queue1, ^{
NSLog(@"任务2 in:---thread:%@---queue:%@", [NSThread currentThread], queue1);
[NSThread sleepForTimeInterval:1.f];
NSLog(@"任务2 in:---thread:%@---queue:%@", [NSThread currentThread], queue1);
});
dispatch_async(queue2, ^{
NSLog(@"任务3 in:---thread:%@---queue:%@", [NSThread currentThread], queue2);
[NSThread sleepForTimeInterval:3.f];
NSLog(@"任务3 in:---thread:%@---queue:%@", [NSThread currentThread], queue2);
});
NSLog(@"---end---, thread:%@", [NSThread currentThread]);
}
目标队列都是使用的串行队列, 多个队列设置targetQueue为一个串行队列以后,
dispatch_async
到该队列的内容, 就好像是dispatch_async
到targeQueue中执行一样.
GCD中的 dispatch group
dispatch group是GCD中专门用来监听多个异步任务(block)的.
dispatch group用来管理各种block, 在被关联到group的block完全执行以后, 通过相关api, 就能够通知当前group, 被添加的block执行完.
group中有两种方式通知当前添加到group的task任务执行完成:
- dispatch_group_wait, 阻塞当前线程, 等待所有任务完成或者等待超, 同步执行block.
- dispatch_group_notify, 会异步执行block, 不会阻塞当前线程.
group也有两种方式将block关联到group中:
- 使用
dispatch_group_async
/dispatch_group_sync
- 使用
dispatch_group_enter
/dispatch_group_leave
注意以下要点:
-
dispatch_group_async
等价于dispatch_group_enter()
和dispatch_group_leave()
的组合。 -
dispatch_group_enter()
必须运行在dispatch_group_leave()
之前。 -
dispatch_group_enter()
和dispatch_group_leave()
需要成对出现的
下面是两种通知方式:
/**
1 ---start---, thread:{number = 1, name = main}
2 ---end 1---, thread:{number = 1, name = main}
// 3.1, 3.2 两步是并行执行的
3.1 任务2 in:---thread:{number = 3, name = (null)}---queue:
3.2 任务1 in:---thread:{number = 4, name = (null)}---queue:
// 4 在3.1, 3.2两步执行完成以后才执行,
4 ---end 2---, thread:{number = 1, name = main}
*/
- (void)dispatchGroupWaitDemo1 {
dispatch_queue_t queue = dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
// 在group中添加任务block
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:3.f];
NSLog(@"任务1 ---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_group_async(group, queue, ^{
NSLog(@"任务2 ---thread:%@---queue:%@", [NSThread currentThread], queue);
});
NSLog(@"---end 1---, thread:%@", [NSThread currentThread]);
// 使用阻塞等待group中的内容执行完成
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"---end 2---, thread:%@", [NSThread currentThread]);
}
/**
1 ---start---, thread:{number = 1, name = main}
2 ---end 1---, thread:{number = 1, name = main}
// 3.1, 3.2是并行执行的
3.1 任务2 ---thread:{number = 3, name = (null)}---queue:
3.2 任务1 ---thread:{number = 4, name = (null)}---queue:
// 异步回调notify
4 ---end 2---, thread:{number = 1, name = main}
*/
- (void)dispatchGroupWaitDemo2 {
dispatch_queue_t queue = dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
// 在group中添加任务block.
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:2.f];
NSLog(@"任务1 ---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_group_async(group, queue, ^{
NSLog(@"任务2 ---thread:%@---queue:%@", [NSThread currentThread], queue);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"---end 2---, thread:%@", [NSThread currentThread]);
});
NSLog(@"---end 1---, thread:%@", [NSThread currentThread]);
}
/**
同dispatchGroupWaitDemo2, 只关心加入到group的block, 并不关心queue
1 ---start---, thread:{number = 1, name = main}
2 ---end 1---, thread:{number = 1, name = main}
3.1 任务1 ---thread:{number = 3, name = (null)}---queue:
3.2 任务2 ---thread:{number = 4, name = (null)}---queue:
4 ---end 2---, thread:{number = 1, name = main}
*/
- (void)dispatchGroupWaitDemo3 {
dispatch_queue_t queue1 = dispatch_queue_create("queue1",DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("queue2",DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
// 在group中添加任务block.
dispatch_group_async(group, queue1, ^{
[NSThread sleepForTimeInterval:2.f];
NSLog(@"任务1 ---thread:%@---queue:%@", [NSThread currentThread], queue1);
});
dispatch_group_async(group, queue2, ^{
[NSThread sleepForTimeInterval:5.f];
NSLog(@"任务2 ---thread:%@---queue:%@", [NSThread currentThread], queue2);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"---end 2---, thread:%@", [NSThread currentThread]);
});
NSLog(@"---end 1---, thread:%@", [NSThread currentThread]);
}
以下是使用dispatch_group_enter
/dispatch_group_leave
将block关联group.
/**
1. ---start---, thread:{number = 1, name = main}
2. ---end 1---, thread:{number = 1, name = main}
3.1 任务1 ---thread:{number = 3, name = (null)}---queue:
3.2 任务2 ---thread:{number = 4, name = (null)}---queue:
4. ---end 2---, thread:{number = 1, name = main}
*/
- (void)dispatchGroupWaitDemo4 {
dispatch_queue_t queue1 = dispatch_queue_create("queue1",DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("queue2",DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
dispatch_group_enter(group);
dispatch_async(queue1, ^{
[NSThread sleepForTimeInterval:2.f];
NSLog(@"任务1 ---thread:%@---queue:%@", [NSThread currentThread], queue1);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue2, ^{
[NSThread sleepForTimeInterval:5.f];
NSLog(@"任务2 ---thread:%@---queue:%@", [NSThread currentThread], queue2);
dispatch_group_leave(group);
});
// 两种通知 group中 block执行完成的方式, 阻塞与非阻塞
// dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"---end 2---, thread:%@", [NSThread currentThread]);
});
NSLog(@"---end 1---, thread:%@", [NSThread currentThread]);
}
dispatch_group_enter
、dispatch_group_leave
必须成对出现
dispatch_group_enter
、dispatch_group_leave
成对出现包裹block, 实际作用与dispatch_group_async
一样, 写法不一样.
/**
1. ---start---, thread:{number = 1, name = main}
2. ---end 1---, thread:{number = 1, name = main}
3.1 任务3 ---thread:{number = 3, name = (null)}---queue:
3.2 任务1 ---thread:{number = 4, name = (null)}---queue:
3.3 任务2 ---thread:{number = 5, name = (null)}---queue:
4. ---end 2---, thread:{number = 1, name = main}
*/
- (void)dispatchGroupWaitDemo5 {
dispatch_queue_t queue1 = dispatch_queue_create("queue1",DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("queue2",DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
dispatch_group_enter(group);
dispatch_async(queue1, ^{
[NSThread sleepForTimeInterval:2.f];
NSLog(@"任务1 ---thread:%@---queue:%@", [NSThread currentThread], queue1);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue2, ^{
[NSThread sleepForTimeInterval:5.f];
NSLog(@"任务2 ---thread:%@---queue:%@", [NSThread currentThread], queue2);
dispatch_group_leave(group);
});
dispatch_group_async(group, queue2, ^{
[NSThread sleepForTimeInterval:1.f];
NSLog(@"任务3 ---thread:%@---queue:%@", [NSThread currentThread], queue2);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"---end 2---, thread:%@", [NSThread currentThread]);
});
NSLog(@"---end 1---, thread:%@", [NSThread currentThread]);
}
GCD中的 dispatch barrier
有时候,我们有这种需求, 有两组操作, 第一组操作都是并发执行, 第二组操作也是互相并发执行, 但是第一组操作和第二组操作之间, 需要完成一个些其他的操作,这组操作不能和其他两组操作并发.
一般有人将 barrier方法成为阻挡块, 会将dispatch_barrier_async
之前加入queue的block先执行完,然后执行 barrier block方法, 然后执行barrier之后的block.
在学习了下一节内容时候, 我们就会知道
dispatch_barrier_async
方法实际是给传递给该方法的block, 增加了一个DISPATCH_BLOCK_BARRIER
属性标记, 我们称这个block为阻挡块. 当有阻挡块标志的block对象直接调用时,此标志无效。
/**
2018-07-04 14:42:32.529311+0800 pthreadDemo[56921:5025231] ---start---, thread:{number = 1, name = main}
2018-07-04 14:42:32.529587+0800 pthreadDemo[56921:5025231] ---end---, thread:{number = 1, name = main}
2018-07-04 14:42:34.534769+0800 pthreadDemo[56921:5025445] 2---{number = 3, name = (null)}
2018-07-04 14:42:34.534782+0800 pthreadDemo[56921:5025447] 1---{number = 4, name = (null)}
2018-07-04 14:42:36.538536+0800 pthreadDemo[56921:5025445] 2---{number = 3, name = (null)}
2018-07-04 14:42:36.538536+0800 pthreadDemo[56921:5025447] 1---{number = 4, name = (null)}
2018-07-04 14:42:38.540485+0800 pthreadDemo[56921:5025447] barrier---{number = 4, name = (null)}
2018-07-04 14:42:40.543862+0800 pthreadDemo[56921:5025447] barrier---{number = 4, name = (null)}
2018-07-04 14:42:42.545779+0800 pthreadDemo[56921:5025445] 4---{number = 3, name = (null)}
2018-07-04 14:42:42.545780+0800 pthreadDemo[56921:5025447] 3---{number = 4, name = (null)}
2018-07-04 14:42:44.547830+0800 pthreadDemo[56921:5025447] 3---{number = 4, name = (null)}
2018-07-04 14:42:44.547830+0800 pthreadDemo[56921:5025445] 4---{number = 3, name = (null)}
*/
- (void)dispatchBarrierAsyncDemo {
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
dispatch_async(queue, ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_barrier_async(queue, ^{
// 追加任务 barrier
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"barrier---%@",[NSThread currentThread]);// 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务4
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"4---%@",[NSThread currentThread]); // 打印当前线程
}
});
NSLog(@"---end---, thread:%@", [NSThread currentThread]);
}
dispatch block
在iOS 8. GCD又增加了很多关于 dispatch_block的属性,以及api:
- 在创建block以后, 可以在它为被调用之前取消
- 通过设置成barrier block(同
dispatch_barrier_async
), 打到阻塞块效果 - 通过
dispatch_block_notify
和dispatch_block_wait
监听某block执行完成.
dispatch_block_create()
dispatch_block_cancel()
dispatch_block_wait()
dispatch_block_notify()
dispatch_block_testCancel()
dispatch_block 有以下dispatch_block_flags_t
:
DISPATCH_ENUM_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
DISPATCH_ENUM(dispatch_block_flags, unsigned long
DISPATCH_BLOCK_BARRIER = 0x01,
DISPATCH_BLOCK_DETACHED = 0x02,
DISPATCH_BLOCK_ASSIGN_CURRENT = 0x04,
DISPATCH_BLOCK_NO_QOS_CLASS = 0x08,
DISPATCH_BLOCK_INHERIT_QOS_CLASS = 0x10,
DISPATCH_BLOCK_ENFORCE_QOS_CLASS = 0x20,
);
-
DISPATCH_BLOCK_BARRIER
, 指示block对象在提交给并发队列时, 应该充当阻挡块的标志。有关详细信息,请参阅dispatch_barrier_async()。当调度块对象直接调用时,此标志无效。 -
DISPATCH_BLOCK_DETACHED
, 指示block对象应当与当前执行上下文属性(如QOS类,os_activity_t和当前IPC请求属性(如果有))脱离关联的标志。如果直接调用,块对象将在调用线程的持续时间内(在应用分配给块对象的属性之前,如果有的话)从调用线程中移除这些属性。如果提交给队列,将使用队列的属性(或专门分配给块对象的任何属性)执行块对象。 - 其他属性参考官方文档...
同时,也可以指定dispatch_qos_class_t
, 指定dispatch_block 的优先级.
相关demo如下, 可以取消, 可以同步/异步等待某block执行完, 可以设置barrier操作.
/**
2018-07-04 16:20:47.179561+0800 pthreadDemo[64925:5298793] ---start---, thread:{number = 1, name = main}
2018-07-04 16:20:49.184556+0800 pthreadDemo[64925:5299137] 1---{number = 4, name = (null)}
2018-07-04 16:20:49.184557+0800 pthreadDemo[64925:5299136] 2---{number = 3, name = (null)}
2018-07-04 16:20:51.187729+0800 pthreadDemo[64925:5299137] 1---{number = 4, name = (null)}
2018-07-04 16:20:51.187769+0800 pthreadDemo[64925:5299136] 2---{number = 3, name = (null)}
2018-07-04 16:20:51.188237+0800 pthreadDemo[64925:5298793] ---end---, thread:{number = 1, name = main}
2018-07-04 16:20:53.193472+0800 pthreadDemo[64925:5299136] 4---{number = 3, name = (null)}
2018-07-04 16:20:53.193472+0800 pthreadDemo[64925:5299137] 3---{number = 4, name = (null)}
2018-07-04 16:20:55.199081+0800 pthreadDemo[64925:5299137] 3---{number = 4, name = (null)}
2018-07-04 16:20:55.199085+0800 pthreadDemo[64925:5299136] 4---{number = 3, name = (null)}
*/
-(void)dispatchBlockDemo1{
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"---start---, thread:%@", [NSThread currentThread]);
dispatch_async(queue, ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
// 创建一个 barrier block
dispatch_block_t block = dispatch_block_create(DISPATCH_BLOCK_BARRIER, ^{
// 追加任务 barrier
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"barrier---%@",[NSThread currentThread]);// 打印当前线程
}
});
dispatch_async(queue,block);
dispatch_async(queue, ^{
// 追加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务4
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"4---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_block_cancel(block);
dispatch_block_wait(block, DISPATCH_TIME_FOREVER);
NSLog(@"---end---, thread:%@", [NSThread currentThread]);
}
一个下载图片中途取消的实例:
func downloadPhotosWithCompletion(completion: BatchPhotoDownloadingCompletionClosure?) {
var storedError: NSError!
let downloadGroup = dispatch_group_create()
var addresses = [OverlyAttachedGirlfriendURLString,
SuccessKidURLString,
LotsOfFacesURLString]
addresses += addresses + addresses // 扩展address数组,复制3份
var blocks: [dispatch_block_t] = [] // 一个保存block的数组
for i in 0 ..< addresses.count {
dispatch_group_enter(downloadGroup)
let block = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS) { // 创建一个block,block的标志是DISPATCH_BLOCK_INHERIT_QOS_CLASS
let index = Int(i)
let address = addresses[index]
let url = NSURL(string: address)
let photo = DownloadPhoto(url: url!) {
image, error in
if let error = error {
storedError = error
}
dispatch_group_leave(downloadGroup)
}
PhotoManager.sharedManager.addPhoto(photo)
}
blocks.append(block)
dispatch_async(GlobalMainQueue, block) // 把这个block放到GlobalMainQueue上异步调用。因为全局队列是一个顺序队列所以方便取消对象block,同时可以保证下载任务在downloadPhotosWithCompletion返回后才开始执行。
}
for block in blocks[3 ..< blocks.count] {
let cancel = arc4random_uniform(2) // 随机返回一个整数,会返回0或1
if cancel == 1 {
dispatch_block_cancel(block) // 如果是1就取消block,这个只能发生在block还在队列中并没有开始的情况下。因为把block已经放到了GlobalMainQueue中,所以这个地方会先执行,执行完了才会执行block。
dispatch_group_leave(downloadGroup) // 因为已经dispatch_group_enter了,所以取消时也要将其都leave掉。
}
}
dispatch_group_notify(downloadGroup, GlobalMainQueue) {
if let completion = completion {
completion(error: storedError)
}
}
}
其他GCD中重要的内容
快速迭代 dispatch_apply
dispatch_apply
函数是dispatch_sync
函数和dispatch group的关联API,该函数按指定的次数, 将指定的block追加到指定的dispatch queue中, 并等到全部的处理执行结束.
/**
1. 0---{number = 1, name = main}
2. 1---{number = 4, name = (null)}
3. 2---{number = 3, name = (null)}
4. 3---{number = 5, name = (null)}
5. 4---{number = 4, name = (null)}
6. The end
*/
- (void)dispatchApplyDemo {
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(5, concurrentQueue, ^(size_t i) {
NSLog(@"%zu---%@",i,[NSThread currentThread]);
});
NSLog(@"The end"); //这里有个需要注意的是,dispatch_apply这个是会阻塞主线程的。这个log打印会在dispatch_apply都结束后才开始执行
}
由于直接使用concurrent queue进行dispatch_async
调用, 会造成线程爆炸, 如果使用dispatch_apply
, 就不会.
dispatch_after
dispatch_after是来延迟执行的GCD方法,因为在主线程中我们不能用sleep来延迟方法的调用,所以用dispatch_after是最合适的.
dispatch_after能让我们添加进队列的任务延时执行,该函数并不是在指定时间后执行处理,而只是在指定时间追加处理到dispatch_queue.
上面是用gcd实现的延时,除了gcd之外,还可以通过NSObject的分类方法:
- [self performSelector:@selector(doSomething) withObject:self afterDelay:2];
- NSTimer的类方法:[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(doSomething) userInfo:nil repeats:NO];
它们在主线程上的执行效果是一样的。在子线程上的话,使用NSObject的分类方法和NSTimer的类方法就得注意了!它们的实现是基于runloop的.
dispatch_semaphore 信号量
dispatch_semaphore
是GCD提供的一种保证同步的方式.
使用dispatch_semaphore_signal
使得信号量+1, 使用dispatch_semaphore_wait
使得信号量-1, 为0时的等待, 保证不同线程同步的目的.
/**
1 start--- 1 {number = 1, name = main}
2 start--- 2 {number = 3, name = (null)}
3 semaphore +1---{number = 3, name = (null)}
4 continue---{number = 1, name = main}
*/
- (void)dispatchSemaphoreDemo {
//创建semaphore
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSLog(@"start--- 1 %@", [NSThread currentThread]);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"start--- 2 %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.f];
NSLog(@"semaphore +1---%@", [NSThread currentThread]);
dispatch_semaphore_signal(semaphore); //+1 semaphore
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"continue---%@", [NSThread currentThread]);
}
虽然这里有更好的线程同步的方式, 比如 dispatch_sync
, dispatch_barrier_async
等等, 这里用信号量的方式可以同步的更加细腻.
其他的同步方法: 各种锁
参考文件
- iOS开发 - 多线程实现方案之GCD篇
- iOS-图文表并茂,手把手教你GCD
- 细说GCD(Grand Central Dispatch)如何用
- iOS GCD/主队列/并行队列/全局队列/串行队列/同步任务/异步任务区别 含代码
参考demo
https://github.com/brownfeng/GCDDemo