首先,我创建一个像这样的串行队列
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。
换句话说,我想在队列中弹出任何等待任务(不是当前正在运行的任务),如果我添加一个新任务。
是否有内置机制或我是否必须自己实现?对于后者,我如何识别队列中的单个任务并将其删除?
答案 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
属性。