Учитывая создание очереди queue2 с целью queue1 (queue2 = dispatch_queue_create_with_target(name, attr, queue1)) ...

Если обе очереди параллельны, ожидает ли dispatch_barrier_async в очереди 2 только опустошение очереди 2 или также ожидает целевую очередь? Когда обе очереди имеют соответствующие блоки барьера в очереди, имеет ли блок барьера queue2 приоритет?

1
xtravar 20 Дек 2018 в 19:40

1 ответ

Лучший ответ

Барьер в очереди не влияет на целевую очередь.

Это легче всего продемонстрировать эмпирически. Например:

- (void)experiment {
    dispatch_queue_t queue1 = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue2 = dispatch_queue_create_with_target("2", DISPATCH_QUEUE_CONCURRENT, queue1);

    dispatch_async(queue1, ^{
        [self taskOnQueue:1 taskNumber:1 color:1];
    });
    dispatch_async(queue2, ^{
        [self taskOnQueue:2 taskNumber:2 color:0];
    });
    dispatch_barrier_async(queue2, ^{
        [self taskOnQueue:2 taskNumber:3 color:0];
    });

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        dispatch_async(queue2, ^{
            [self taskOnQueue:2 taskNumber:4 color:0];
        });
        dispatch_async(queue1, ^{
            [self taskOnQueue:1 taskNumber:5 color:1];
        });
    });
}

Задачи 1-3 отправляются немедленно, а задачи 4 и 5 отправляются через 0,5 секунды. Задача 3 использует барьер. Задачи 1 и 5 находятся на queue1, а задачи 2–4 находятся на queue2. Все задачи занимают по одной секунде.

Это приводит к следующему. (Я вручную выделил эти номера задач, чтобы прояснить это.)

enter image description here

Вы можете видеть, что задача № 5 в очереди 1 запускается, как только она помещается в очередь, даже если (а) это была последняя задача в очереди и (б) очередь 2 имеет барьер для задачи № 3. Однако вторая очередь учитывает барьер задачи 3.

К вашему сведению, это служебные методы, которые генерируют эти интересные места:

- (void)taskOnQueue:(uint32_t)code taskNumber:(uint32_t)arg1 color:(uint32_t)arg4 {
    [self pointOfInterest:code arg1:arg1 color:arg4 block:^{
        [NSThread sleepForTimeInterval:1];
    }];
}

- (void)pointOfInterest:(uint32_t)code arg1:(uint32_t)arg1 color:(uint32_t)arg4 block:(void (^)(void))block {
    kdebug_signpost_start(code, arg1, 0, 0, arg4);
    block();
    kdebug_signpost_end(code, arg1, 0, 0, arg4);
}

NB: Обратное - совсем другое дело. Очереди будут затронуты, если их целевая очередь имеет барьер. Если целевая очередь заблокирована (например, если вы измените задачу 3 на выполнение с барьером в целевой очереди, queue1), то задачи во второй очереди будут ждать, пока ее целевая очередь не освободится:

- (void)experiment2 {
    dispatch_queue_t queue1 = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue2 = dispatch_queue_create_with_target("2", DISPATCH_QUEUE_CONCURRENT, queue1);

    dispatch_async(queue1, ^{
        [self taskOnQueue:1 taskNumber:1 color:1];
    });
    dispatch_async(queue2, ^{
        [self taskOnQueue:2 taskNumber:2 color:0];
    });
    dispatch_barrier_async(queue1, ^{              // changed to queue 1
        [self taskOnQueue:1 taskNumber:3 color:1];
    });

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        dispatch_async(queue2, ^{
            [self taskOnQueue:2 taskNumber:4 color:0];
        });
        dispatch_async(queue1, ^{
            [self taskOnQueue:1 taskNumber:5 color:1];
        });
    });
}

Это приведет к:

enter image description here

Здесь задача 3 была отправлена ​​с барьером (где находится этот первый указатель Ⓢ), и она не только не запускалась, пока задача 1 не была выполнена в целевой очереди, но и задача 4 (выполнялась во второй очереди) во второй очереди ( отправлено туда, где находится этот второй указатель Ⓢ) также ожидал этого барьера в целевой очереди своей очереди, как и задача 5.

3
Rob 21 Дек 2018 в 14:58