5

到目前为止,我已经浏览了 GCD 的文档,但是似乎缺少 dispatch_cancel() ,我想用它来取消所有调度的块调用。有没有办法实现 dispatch_cancel()?

4

3 回答 3

10

正如@HampusNilsson 所提到的,您无法合理地取消非垃圾收集环境(例如此)中的任何正在进行的操作,因为它会固有地泄漏资源并使进程处于不确定状态。NSOperationQueue有一个cancel API,这个API可以用来实现in-flight操作的取消,前提是操作本身是协同检查flag,然后清理并提前返回。这不是真正的硬中止。

至于取消排队但未开始的工作项目,是的,可以NSOperationQueue处理这个,但这需要一些额外的费用,并且NSOperationQueue是更高级别的抽象。GCD 的性能很大程度上取决于内部使用无锁队列。无锁队列将比基于锁的实现更快,但为了达到这种速度,它需要进行某些权衡。例如,我希望以无锁方式任意改变队列以删除取消的操作会更加困难。我怀疑将暴露的队列操作限制为“仅入队”并使工作项本身不可变(块和函数 ptrs)为许多优化打开了大门,这些优化使 GCD 的开销如此之小并且性能如此之好。

FWIW,在常见情况下,在现有 GCD API 之上实现可取消操作非常简单,因此任何需要此功能的人都可以自己轻松完成(并且可能以更适合他们特定需求的方式比一般化的 API)。考虑以下函数——它将一个块入队并返回一个块,您可以稍后调用它来取消入队操作:

dispatch_block_t dispatch_cancelable_async(dispatch_queue_t q, dispatch_block_t b)
{
    __block uintptr_t isCancelled = 0;
    dispatch_async(q, ^{
        if (!isCancelled) b();
    });
    return [[^{ isCancelled = 1; } copy] autorelease];
}

对于每种情况,这不是正确的取消方法,但它是一个不错的初步近似值。

“使用完成工作的最高级别的抽象。” 如果您想要取消,并且和 GCD 之间的开销差异NSOperationQueue不是一个重要因素,您应该只使用NSOperationQueue. 有些人甚至会争辩说,NSOperationQueue在使用 Objective-C 时,使用是更惯用的选择。除此之外,如图所示,在 GCD 之上为常见情况实施非中止取消是相当简单的。

基于这一切,我怀疑在性能和复杂性方面建立 API 的取消是不值得的。

于 2013-09-12T13:20:52.820 回答
2


从 iOS 8 及更高版本您可以使用dispatch_block_cancel取消块执行

dispatch_block_t blockTask = dispatch_block_create(0,{
 //do some task
});
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,5*NSEC_PER_SEC);
dispatch_after(time,dispatch_get_main_queue(),blockTask);

dispatch_block_cancel(blockTask);
于 2016-11-29T21:13:07.483 回答
0

GCD 没有实现取消 API,因为它不安全(它可能会中止线程操作)。如果您想取消任务,您需要通过实现“已取消”布尔值自己完成,并在任务开始时和稍后定期检查它。

于 2013-09-12T07:56:55.870 回答