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

chr*_*oph 12 objective-c grand-central-dispatch ios

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

static dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
Run Code Online (Sandbox Code Playgroud)

然后,在某个未知的时间点,任务会像这样添加到队列中

dispatch_async(queue, ^{
    // do something, which takes some time
});
Run Code Online (Sandbox Code Playgroud)

如果第一个任务尚未完成,则新任务将等到第一个任务完成(当然这是串行队列的用途).

但是如果我向队列中添加5个新任务,而原来的第一个任务仍然在运行,我不想执行新的任务1,然后是2号,然后是3号,依此类推,但是想要获得删除任务1到4,并在原始第一个任务完成后直接开始执行任务5.

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

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

Jod*_*ins 18

将块提交到GCD调度队列后,它将运行.没有办法取消它.如您所知,您可以实现自己的机制,以便尽早"中止"块执行.

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

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


chr*_*oph 5

随着大卫的回答让我走上正轨,我成功地做到了这样

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

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

  • 我相信您知道,但该实现不是线程安全的。如果多个线程调用此代码,您将丢弃 taskCounter。 (2认同)