Подтвердить что ты не робот

GCD: Как удалить задачи ожидания из последовательной очереди?

Сначала я создаю последовательную очередь, подобную этой

static dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);

то в какой-то неизвестный момент времени задача добавляется в очередь, подобную этой

dispatch_async(queue, ^{
    // do something, which takes some time
});

Если первая задача еще не завершена, новая задача будет ждать завершения первого (что, конечно, для очереди последовательных).

Но если я добавлю 5 новых задач в очередь, в то время как первая первая из них все еще запущена, я не хочу выполнять новую задачу №1, затем №2, затем № 3 и т.д., но хотите избавиться от задач с 1 по 4 и сразу начать выполнение задачи №5 после завершения первоначальной первой задачи.

Другими словами, я хочу поместить любую ожидающую задачу (а не ту, которая в данный момент выполняется) из очереди, если я добавлю новую.

Есть ли механизм сборки для этого или я должен сам реализовать это? И для последнего, как бы я идентифицировал отдельные задачи внутри очереди и удалил их?

4b9b3361

Ответ 1

Как только блок отправлен в очередь отправки GCD, он будет запущен. Отменить его невозможно. Вы можете, как вы знаете, реализовать свой собственный механизм, чтобы "прервать" выполнение блока раньше.

Более простой способ сделать это - использовать NSOperationQueue, поскольку он уже предоставляет реализацию для отмены ожидающих операций (т.е. тех, которые еще не запущены), и вы можете легко вставить в ячейку новый элемент ish addOperationWithBlock.

Хотя NSOperationQueue реализован с использованием GCD, я считаю, что GCD намного проще использовать в большинстве случаев. Однако в этом случае я бы серьезно подумал об использовании NSOperationQueue, потому что он уже обрабатывает отложенные операции.

Ответ 2

То, как вы справляетесь с этим, - это использовать ivar, который указывает на блоки в очереди, которые они должны просто вернуть:

^{
  if(!canceled) {
    ... do work
  }
}

Вам также не нужно использовать простое логическое значение - вы можете сделать это более сложным, но общая идея состоит в том, чтобы использовать один или несколько ivars, чтобы блокировать запросы, прежде чем что-либо делать.

Я использую эту технику (но не изобретаю ее) с большим успехом.

Ответ 3

С ответом Давидса, который меня заводил, мне удалось сделать это так

taskCounter++;
dispatch_async(queue, ^{
    if (taskCounter > 1) {
        taskCounter--;
        NSLog(@"%@", @"skip");
        return;
    }
    NSLog(@"%@", @"start");
    // do stuff
    sleep(3);
    taskCounter--;
    NSLog(@"%@", @"done");
});

taskCounter должен быть либо ivar, либо свойством (инициализировать его с помощью 0). В этом случае ему даже не нужен атрибут __block.