GCD:如何从串行队列中删除等待任务?

时间:2012-09-07 11:24:13

标签: objective-c ios grand-central-dispatch

首先,我创建一个像这样的串行队列

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。

换句话说,我想在队列中弹出任何等待任务(不是当前正在运行的任务),如果我添加一个新任务。

是否有内置机制或我是否必须自己实现?对于后者,我如何识别队列中的单个任务并将其删除?

3 个答案:

答案 0 :(得分:18)

一旦将块提交到GCD调度队列,它就会运行。没有办法取消它。如您所知,您可以实现自己的机制,以便尽早“中止”块执行。

更简单的方法是使用NSOperationQueue,因为它已经提供了取消挂起操作(即那些尚未运行的操作)的实现,并且您可以轻松地使用new-ish将块排入队列addOperationWithBlock方法。

尽管NSOperationQueue是使用GCD实现的,但我发现GCD在大多数情况下更容易使用。但是,在这种情况下,我会认真考虑使用NSOperationQueue,因为它已经处理了取消挂起操作。

答案 1 :(得分:4)

你处理这个问题的方法是使用一个ivar来指示它们应该返回的排队块:

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

您也不需要使用简单的布尔值 - 您可以使其更复杂 - 但一般的想法是在执行任何操作之前使用块查询的一个或多个ivars。

我使用这种技术(但没有发明它)取得了巨大的成功。

答案 2 :(得分:4)

随着戴维斯的回答让我走上正轨,我成功地这样做了

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

taskCounter必须是ivar或属性(使用0初始化它)。在这种情况下,它甚至不需要__block属性。