Perguntas comuns da entrevista do GCD no iOS

Exemplo 1

- (void)surpassNum

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

Resultado : O resultado da impressão é >=500

Análise :

  1. Ao entrar no loop pela primeira vez, self.num = 0, e uma tarefa assíncrona é criada neste momento, mas essa tarefa não é necessariamente executada imediatamente, ela aguardará o agendamento de primeira saída e, em seguida, entrará no Como a tarefa é executada, então self.num++ não é executado, então no segundo loop, self.num ainda é igual a 0, e uma nova tarefa assíncrona será criada neste momento, e assim por diante, pelo menos 500 tarefas assíncronas serão comuns.

  2. Como self.num<500 é usado como condição de término no loop while, somente quando self.num >=500 ele pode sair do loop e imprimir

  3. No meio do salto para fora do loop para executar a impressão, pode haver várias tarefas assíncronas executadas, o que equivale a self.num++ sendo executado N vezes

  4. Portanto, o resultado da impressão deve ser >=500

Extensão: Se dispatch_async for substituído pela tarefa de sincronização dispatch_sync, o resultado da impressão deverá ser 500, pois a tarefa de sincronização bloqueará o encadeamento e o próximo loop não poderá ser executado até que self.num++ seja executado.

Exemplo 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);
}
复制代码

Resultado : Imprimir resultado 0-999 Análise :

  1. O loop for é usado aqui, e a variável temporária i é usada em vez de self.num para julgamento. Self.num não tem nada a ver com o loop, então apenas 999 loops são executados aqui, ou seja, 999 tarefas assíncronas são criadas.

  2. Quando i== 1000, o loop for termina. Embora 999 tarefas assíncronas sejam criadas neste momento, essas tarefas são concluídas? Obviamente não, ele precisa aguardar o agendamento da thread; então, antes de imprimir, quantas tarefas podem ser executadas? , isso é incerto, talvez uma tarefa não tenha sido executada, talvez todas executadas, então o resultado da impressão pode ser 0-999

  3. Embora seja teoricamente 0-999, o resultado da impressão ainda será próximo a 999

Exemplo 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");
    });
}
复制代码

P: Qual é a possível razão para a impressão acima?

  • R: 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 异常错误

Acho que você gosta

Origin juejin.im/post/7081582721415249950
Recomendado
Clasificación