Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
345 views
in Technique[技术] by (71.8m points)

ios - Is there any way to implement dispatch_cancel()?

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()?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...