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 после завершения первоначальной первой задачи.
Другими словами, я хочу поместить любую ожидающую задачу (а не ту, которая в данный момент выполняется) из очереди, если я добавлю новую.
Есть ли механизм сборки для этого или я должен сам реализовать это? И для последнего, как бы я идентифицировал отдельные задачи внутри очереди и удалил их?
Ответы
Ответ 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
.