有没有办法实现dispatch_cancel()?

Ric*_*ard 4 grand-central-dispatch ios

到目前为止,我已经阅读了GCD的文档,但是似乎错过了dispatch_cancel(),我想用它来取消所有调度的块调用.有没有办法实现dispatch_cancel()?

ipm*_*mcc 10

正如@HampusNilsson所提到的,你无法在非垃圾收集环境(例如这个)中合理地取消任何正在进行的操作,因为它本身会泄漏资源并使进程处于不确定状态.NSOperationQueue具有取消API,并且该API可用于实现取消正在进行的操作,前提是操作本身正在协作检查标志,然后提前清理并返回.这不是真正的,难以中止的.

至于取消入队但尚未开始的工作项,是的,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];
}
Run Code Online (Sandbox Code Playgroud)

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

"使用最高级别的抽象来完成工作." 如果你想要取消,并且NSOperationQueue和GCD 之间的开销差异不是一个重要因素,你应该使用NSOperationQueue.有些人甚至认为NSOperationQueue在Objective-C中工作时使用是更惯用的选择.除此之外,如图所示,对GCD之上的常见情况实施非中止取消是相当微不足道的.

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


Ham*_*son 0

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