Preguntas de entrevista comunes de GCD en iOS

Ejemplo 1

- (void)surpassNum

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

Resultado : el resultado de la impresión es >=500

Análisis :

  1. Al ingresar al ciclo por primera vez, self.num = 0, y se crea una tarea asíncrona en este momento, pero esta tarea no necesariamente se ejecuta de inmediato, esperará la programación de primera salida y luego ingresará al siguiente ciclo Dado que la tarea se ejecuta, Self.num ++ no se ejecuta, por lo que en el segundo ciclo, self.num sigue siendo igual a 0, y se creará una nueva tarea asíncrona en este momento, y así sucesivamente, al menos 500 tareas asíncronas serán comunes.

  2. Dado que self.num<500 se usa como condición de terminación en el ciclo while, solo cuando self.num >=500 puede saltar fuera del ciclo e imprimir

  3. En medio de saltar fuera del ciclo para ejecutar la impresión, puede haber varias tareas asincrónicas ejecutadas, lo que equivale a que self.num++ se ejecute N veces

  4. Entonces el resultado de la impresión debe ser >=500

Extensión: si dispatch_async se reemplaza por la tarea de sincronización dispatch_sync, el resultado de la impresión debe ser 500, porque la tarea de sincronización bloqueará el subproceso y el siguiente bucle no se podrá ejecutar hasta que se ejecute self.num++.

Ejemplo 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álisis :

  1. El ciclo for se usa aquí, y la variable temporal i se usa en lugar de self.num para el juicio. Self.num no tiene nada que ver con el ciclo, por lo que aquí solo se ejecutan 999 ciclos, es decir, se crean 999 tareas asíncronas.

  2. Cuando i== 1000, el bucle for termina. Aunque se crean 999 tareas asincrónicas en este momento, ¿se completan estas tareas? Obviamente no, debe esperar a que se programe el hilo; entonces, antes de imprimir, ¿cuántas tareas se pueden ejecutar? , esto es incierto, tal vez una tarea no se ejecutó, tal vez se ejecutó por completo, entonces el resultado de la impresión puede ser 0-999

  3. Aunque teóricamente es 0-999, el resultado de la impresión seguirá estando cerca de 999

Ejemplo 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: ¿Cuál es la posible razón de la impresión anterior?

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

Supongo que te gusta

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