Is there a way to implement dispatch_cancel ()?

So far, I went through the GCD document, but it seems that dispatch_cancel () is missing there, which I want to use to cancel all calls to the distribution blocks. Is there a way to implement dispatch_cancel ()?

+4
source share
3 answers

As @HampusNilsson mentions, you cannot intelligently cancel any flight operation in a non-garbage environment (like this), because it will inherently leak resources and leave the process in an undefined state. NSOperationQueue has an undo API, and this API can be used to undo in-flight operations, provided that the operations themselves jointly check the flag and then clear and return at an early stage. This is not true, it is difficult to interrupt.

Regarding the cancellation of work items with enabled but not started, yes, NSOperationQueue handles this, but this comes at the cost of some extra expense, and NSOperationQueue a higher level of abstraction. GCD performance is mainly based on the internal use of loose queues. Stopping without locking will be faster than locking based implementation, but it will take some trade-offs to achieve this speed. For example, I would expect it to be much harder to arbitrarily mutate a queue in lock mode to remove a canceled operation. I suspect that restricting open queue operations to “only in the queue” and creating immutable work items (ptrs blocks and functions) has opened the door to many optimizations that allow the GCD to have such little overhead and work so well.

FWIW, in general, makes undo operations pretty trivial to implement on top of the existing GCD API, so anyone who needs this feature can do it quite easily (and probably in a way that is better suited to their specific needs, than a generic API). Consider the following function: it puts a block in a queue and returns a block, which you could call later, to cancel the operation installed in the queue:

 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 will not be the right undo method for each case, but this is a decent first approximation.

"Use the highest level abstraction that does the job." If you want to cancel, and the difference in overhead between NSOperationQueue and GCD is not a significant factor, you should simply use NSOperationQueue . Some even suspect that using NSOperationQueue is a more idiomatic choice when working in Objective-C. In addition, the implementation of cancellation without interruption for the general case on top of the GCD is, as shown, quite trivial.

Based on all this, my suspicion is that building with the API canceled was not a reasonable compromise in terms of performance and complexity.

+10
source

GCD does not implement the undo API, as it would not be safe (it could interrupt work in the middle). If you want to cancel tasks, you need to do it yourself by executing the “canceled” logical process and checking it in your tasks when they start, and then periodically.

0
source

from iOS 8 and above, you can cancel block execution using 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); 
0
source

Source: https://habr.com/ru/post/1501789/


All Articles