1、在主线程执行以下代码打印结果是什么?

  1. - (void)test {
  2. NSLog(@"1");
  3. dispatch_queue_t queue = dispatch_get_main_queue();
  4. dispatch_sync(queue, ^{
  5. NSLog(@"2");
  6. });
  7. NSLog(@"3");
  8. }

打印结果:

  1. ~: 1

并报错: Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
分析原因:
test方法是在主线程里执行的任务(任务1),已经进入主队列当中。
在test方法内部追加了一个同步执行的任务(任务2),dispatch_sync的特点是要在当前线程马上执行,执行完毕后才会继续往下执行。
由于主队列是串行队列,需要依次执行任务,所以任务2要等待任务1执行结束才能执行。
而又因为任务1要等待任务2执行结束才算执行结束。
这样就造成了相互等待的情况,也就是线程死锁,导致代码无法继续执行。
image.png

2、在主线程执行以下代码打印结果是什么?

  1. - (void)test {
  2. NSLog(@"1");
  3. dispatch_queue_t queue = dispatch_get_main_queue();
  4. dispatch_async(queue, ^{
  5. NSLog(@"2");
  6. });
  7. NSLog(@"3");
  8. }

打印结果:

  1. ~: 1
  2. ~: 3
  3. ~: 2

和上面代码唯一的区别就是换成了dispatch_async执行,dispatch_async的特点是不要求马上执行,会等上一个任务执行完成再执行。所以不会造成死锁。
image.png

3、在主线程执行以下代码打印结果是什么?

  1. - (void)test {
  2. NSLog(@"1");
  3. // 创建串行队列
  4. dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
  5. dispatch_async(queue, ^{
  6. NSLog(@"2");
  7. dispatch_sync(queue, ^{
  8. NSLog(@"3");
  9. });
  10. NSLog(@"4");
  11. });
  12. NSLog(@"5");
  13. }

打印结果:

  1. ~: 1
  2. ~: 5
  3. ~: 2

分析原因:
test是在主线程里执行的任务。
创建新的queue是串行队列,又使用async执行任务(任务1),所以会开启新的线程,在新线程里执行。
在任务1中添加了一个sync任务(任务2),由于queue是串行,所以又造成了和问题一同样的情况。
任务2要求马上执行,而任务2又要等待任务1执行完毕才会执行,任务1又要等待任务2执行结束才算完成,这样相互等待造成死锁。
image.png

4、在主线程执行以下代码打印结果是什么?

  1. - (void)test {
  2. NSLog(@"1");
  3. // 创建并发队列
  4. dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
  5. dispatch_async(queue, ^{
  6. NSLog(@"2");
  7. dispatch_sync(queue, ^{
  8. NSLog(@"3");
  9. });
  10. NSLog(@"4");
  11. });
  12. NSLog(@"5");
  13. }

打印结果:

  1. ~: 1
  2. ~: 5
  3. ~: 2
  4. ~: 3
  5. ~: 4

分析原因:
和上一个问题的差别就是任务1和任务2是在并发队列里执行,并发队列的特点就是可以同时执行多个任务。
所以即使任务2需要马上执行,但是任务1也会同步执行,所以不会造成死锁。
image.png

5、总结

使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁)