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.
from iOS 8 and higher you can cancel block execution with
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With