有没有办法实现dispatch_cancel()? [英] Is there any way to implement dispatch_cancel()?

查看:236
本文介绍了有没有办法实现dispatch_cancel()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

解决方案

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



至于取消入队但尚未开始的工作项,是的, NSOperationQueue 处理这个问题,但这需要额外的费用, NSOperationQueue 是一个更高级别的抽象。 GCD的性能很大程度上取决于无锁队列的内部使用。无锁队列比基于锁的实现更快,但是为了达到这个速度,需要进行一些权衡。例如,我希望以无锁方式任意改变队列来删除已取消的操作要困难得多。我怀疑将公开的队列操作限制为仅排队,并使工作项本身不可变(块和函数ptrs),为许多优化提供了大门,这些优化允许GCD具有如此小的开销并且运行良好。 / p>

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;复制] autorelease];
}

对于每个案例,这都不是正确的取消方法,但它是一个体面的初步近似。



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



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


So far I have gone through the doc of GCD, however it seems there misses dispatch_cancel() which I want to use it to cancel all dispatch's blocks invocation. Is there any way to implement dispatch_cancel()?

解决方案

As @HampusNilsson mentions, you can't reasonably cancel any in-flight operation in a non-garbage collected environment (such as this) because it would inherently leak resources and leave the process in an indeterminate state. NSOperationQueue has a cancellation API, and that API can be used to implement cancellation of in-flight operations, provided that the operations themselves are cooperatively checking the flag and then cleaning up and returning early. It's not a true, hard abort.

As for canceling enqueued-but-not-started work items, yes, NSOperationQueue handles this, but that comes at some additional expense, and NSOperationQueue is a higher level of abstraction. GCD's performance is largely predicated on the internal use of lock-free queues. A lock-free queue is going to be faster than a lock-based implementation, but it's going to require certain trade-offs in order to achieve that speed. For instance, I would expect it to be much harder to arbitrarily mutate the queue in a lock free manner to remove a cancelled operation. I suspect that limiting the exposed queue operations to "enqueue only," and making the work items themselves immutable (blocks and function ptrs), opened the door for many of the optimizations that allow GCD to have such little overhead and perform so well.

FWIW, in the common case, making operations cancel-able is pretty trivial to implement on top of the existing GCD API, so anyone who needs this functionality can pretty easily do it themselves (and likely in a way that's better suited to their specific needs than a generalized API would be). Consider the following function -- it enqueues a block on a queue and returns a block that you could call later to cancel the enqueued operation:

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];
}

This won't be the right cancellation method for every case, but it's a decent first approximation.

"Use the highest-level abstraction that gets the job done." If you want cancellation, and the difference in overhead between NSOperationQueue and GCD is not a significant factor, you should just use NSOperationQueue. Some would even go as far as to argue that using NSOperationQueue is the more idiomatic choice when working in Objective-C. Beyond that, implementing non-aborting cancellation for the common case on top of GCD is, as shown, reasonably trivial.

Based on all that, my suspicion is that building in cancellation to the API was not a worthwhile trade-off in terms of performance and complexity.

这篇关于有没有办法实现dispatch_cancel()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆