GCD common interview questions in iOS

Example 1

- (void)surpassNum

{
    while (self.num < 500) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.num++;
        });
    }
    NSLog(@"num is %d",self.num);
}
复制代码

Result : The print result is >=500

Analysis :

  1. When entering the loop for the first time, self.num = 0, and an asynchronous task is created at this time, but this task is not necessarily executed immediately, it will wait for the first-out scheduling, and then it will enter the next loop. Since the task is executed, So self.num++ is not executed, so in the second loop, self.num is still equal to 0, and a new asynchronous task will be created at this time, and so on, at least 500 asynchronous tasks will be common.

  2. Since self.num<500 is used as the termination condition in the while loop, only when self.num >=500 can it jump out of the loop and print

  3. In the middle of jumping out of the loop to execute printing, there may be multiple asynchronous tasks executed, which is equivalent to self.num++ being executed N times

  4. So the print result must be >=500

Extension: If dispatch_async is replaced by dispatch_sync synchronization task, the print result must be 500, because the synchronization task will block the thread, and the next loop cannot be executed until self.num++ is executed.

Example 2

- (void)fixNum
{
    for(int i= 0; i < 1000; i++){
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.num++;
        });
    }
    NSLog(@"fix num is %d", self.num);
}
复制代码

Result : Print result 0-999 Analysis :

  1. The for loop is used here, and the temporary variable i is used instead of self.num for judgment. Self.num has nothing to do with the loop, so only 999 loops are executed here, that is, 999 asynchronous tasks are created.

  2. When i== 1000, the for loop terminates. Although 999 asynchronous tasks are created at this time, are these tasks completed? Obviously not, it needs to wait for the thread to schedule; so before printing, how many tasks can be executed? , this is uncertain, maybe a task has not been executed, maybe all executed, then the print result may be 0-999

  3. Although it is theoretically 0-999, the print result will still be close to 999

Example 3

- (void)asynDemo

{
    dispatch_queue_t queue = dispatch_queue_create("com.qihu", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"1");
    });

    dispatch_async(queue, ^{
        NSLog(@"2");
    });

    dispatch_sync(queue, ^{
        NSLog(@"3");
    });

    NSLog(@"0");

    dispatch_async(queue, ^{
        NSLog(@"4");
    });

    dispatch_async(queue, ^{
        NSLog(@"5");
    });
    dispatch_async(queue, ^{
        NSLog(@"6");
    });
}
复制代码

Q: What is the possible reason for the above printout?

  • A: 1230456
  • B: 1234560
  • C: 3120465
  • D: 2134560

答: A和C 分析

  1. 任务3为同步任务,同步任务有个特性就是会阻塞线程的执行,所以在任务3未执行完毕之前,任务0以及之后的任务都会处于阻塞状态,所以3必定在0之前打印
  2. 然后根据函数的按顺序执行的规律,任务0必定会在 4、5、6 之前进行打印
  3. 异步任务之间是无序的,所以 1、2、3 之间顺序不定,4、5、6 之间顺序也是不定

如果 queue 是 DISPATCH_QUEUE_SERIAL 类型的串行队列的话则答案是 A

示例4

- (void)barrierTest
{
    dispatch_queue_t queue = dispatch_queue_create("com.barrier", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"1");
    });

    dispatch_async(queue, ^{
        NSLog(@"2");
    });

    dispatch_barrier_async(queue, ^{
        NSLog(@"3");
    });

    dispatch_async(queue, ^{
        NSLog(@"4");
    });

}
复制代码

结果:

1234 或 2134

分析:

  1. queue 是一个 DISPATCH_QUEUE_CONCURRENT 类型的并发队列,所以任务1和任务2顺序是不定的

 2. 任务3使用了 dispatch_barrier_async 栅栏函数来创建任务,它有个特点,就是会将前后任

 务进行隔离,任务1和任务2必须都执行完了才会执行任务3,任务4必须等任务3执行完了才能执行

 3. 所以任务3在任务1和任务2之后,但是在任务4之前

示例5

- (void)asynDemo1

{
    dispatch_queue_t queue = dispatch_queue_create("com.demo", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"1");
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_async(queue, ^{
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    NSLog(@"5");
}
复制代码

结果:

15243

分析:

  1. 按执行顺序,先打印1

 2. dispatch_async创建了异步线程,在后台等待,继续往下执行打印5

 3. 异步任务被调用后,先打印2,然后创建一个新异步任务等待调度执行,继续往下执行打印4

 4. 最后打印3

示例6

- (void)syncdemo2 {
    dispatch_queue_t queue = dispatch_queue_create("com.demo", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"1");
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_sync(queue, ^{ NSLog(@"3"); });
        NSLog(@"4");
    });
    NSLog(@"5");
}
复制代码

结果:

15234

分析:

  1. 按顺序执行,先打印 1

 2. dispatch_async 创建了异步任务,在后台等待执行,继续往下执行打印 5

 3. 异步任务被调用后,先打印 2

 4. 创建一个同步任务堵塞线程,等待同步任务执行完毕后才能继续往下执行,所以打印 3

 5. 最后打印 4

示例7

- (void)deadLockTest
{
    dispatch_queue_t queue = dispatch_queue_create("com.demo", NULL);
    NSLog(@"1");
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_sync(queue, ^{
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    NSLog(@"5");
}
复制代码

结果:

152崩溃

分析:

  1. 按顺序执行,先打印1

 2. dispatch_async创建了异步任务,在后台等待执行,继续往下执行打印5

 3. 异步任务被调用,先打印2

 4. 创建一个同步任务3,由于queue是串行队列,任务3需要等待异步任务执行完毕后才能执行,但是异步任务     又需要等待任务3执行完毕后才能继续往下执行打印4,你依赖我,我依赖你,这里就造成了死锁,最终导致     EXC_BAD_INSTRUCTION 异常错误

Guess you like

Origin juejin.im/post/7081582721415249950