Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

kill items in a dispatch_async queue in iOS

I am running a bunch of items in the background using dispatch_async and sometimes I want to kill what I have in the queue - is this possible? For instance this code is run on a view, and then the user goes back a screen. All of these fired actions keep running regardless of the back navigation. Ideally I would like to kill these items from running:

dispatch_async(dispatch_get_global_queue(2, 0), ^{
        for (int i=0; i<[self.manufacturers count]; i++) {
            NSString *manufacturerID = [[[self.manufacturers objectAtIndex:i] ManufacturerID] stringValue];
            [self doSync:manufacturerID withIndex:i setTimer:YES];
        }
    });

If I create a queue and name it and then release it on the dealloc of the view this is called in they still continue to run.

like image 535
Slee Avatar asked Mar 03 '12 13:03

Slee


2 Answers

There's no explicit provision in dispatch queues for termination. In order to do this, it is somewhat common to test an escape location to determine termination. Basically, it'd be a semaphore.

NSOperationQueue (a higher level abstraction, but still build using GCD underneath) does have support for canceling operations. So, for example, you can create a series of NSOperations and add them to an NSOperationQueue and then message -cancelAllOperations to the queue when you don't need it to complete.

A lot of the architecture you choose will depend on how many of these are operating and whether they have different triggers. Among the implementations, NSOperation is likely the "cleanest" solution, since you have an arbitrary queue which you can watch for operations to be finished on and you can also cancel outstanding operations. Further down the scale of hack would be a volatile location that each of these blocks watch inside of a tight loop to determine if they're going to finish prematurely. Yet further down would be a global variable for the same basic function.

In the end, even the implementation of NSOperation involves a test in order to exit in a consistent location (since just killing a thread might result in inconsistencies in the data being operated upon or in allocations/retrains).

like image 54
gaige Avatar answered Oct 07 '22 02:10

gaige


The best way to do this is to create your own concurrent queue (not use one of the global ones) and then call dispatch_suspend() on the queue when you want to stop processing in it. At that point read this: Dispatch queues: How to tell if they're running and how to stop them

Using a cancellation flag will let you then resume the queue such that all the remaining blocks basically just exit (after doing whatever memory management they need to do, like freeing resources) when you resume it again. You can also dispatch_release() the queue immediately after resuming it.

like image 42
jkh Avatar answered Oct 07 '22 01:10

jkh