Suspending GCD query problem

33,586

Solution 1

Any blocks that have been dispatched to your queue asynchronously before you actually call dispatch_suspend() will get run before the suspend takes effect. In your code you are firing off a bunch of blocks asynchronously, so some are probably still in the queue when you call test(2), and those blocks will be executed.

If you want to be able to cancel your running jobs, you'll need to do so in your own logic. GCD purposefully doesn't expose a true cancellation API. You could do something like this:

@interface Canceller
{
    BOOL _shouldCancel;
}
- (void)setShouldCancel:(BOOL)shouldCancel;
- (BOOL)shouldCancel;
@end

@implementation Canceller
- (void)setShouldCancel:(BOOL)shouldCancel {
    _shouldCancel = shouldCancel;
}
- (BOOL)shouldCancel {
    return _shouldCancel;
}
@end

static void test(int a){
    static Canceller * canceller = nil;

    if(q){
        [canceller setShouldCancel:YES];
        [canceller release];
        dispatch_suspend(q);
        dispatch_release(q);
        q=nil;
    }
    canceller = [[Canceller alloc] init];
    q=dispatch_get_global_queue(0,0);
    dispatch_async(q,^ {
        while(![canceller shouldCancel]){NSLog(@"query %d",a);sleep(2);}
    });

}

In this way, each block will keep a reference to an object that knows if it should stop doing work.

Solution 2

From Apple GCD Reference:

dispatch_suspend

By suspending a dispatch object, your application can temporarily prevent the execution of any blocks associated with that object. The suspension occurs after completion of any blocks running at the time of the call. Calling this function increments the suspension count of the object, and calling dispatch_resume decrements it. While the count is greater than zero, the object remains suspended, so you must balance each dispatch_suspend call with a matching dispatch_resume call.

[bold mine]

I assume that this is so because when a block is executed, it leaves the queue. So, it seems you can't suspend a block already in execution.

Share:
33,586
Kostas.N
Author by

Kostas.N

Updated on August 24, 2022

Comments

  • Kostas.N
    Kostas.N over 1 year

    i have trouble suspending a gcd query. Here is some code that demonstrates the problem:

    static dispatch_queue_t q=nil;
    
    static void test(int a){
        if(q){
            dispatch_suspend(q);
            dispatch_release(q);
            q=nil;
        }
        q=dispatch_get_global_queue(0,0);
        dispatch_async(q,^ {
            while(1){NSLog(@"query %d",a);sleep(2);}
        });
    
    }
    
    int main(int argc, const char* argv[]){
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        test(1);
    
        //blah blah blah
    
        test(2);
    
        while(1){}
        [pool release];
        return 0;
    }
    

    What I'm trying to do is suspend,release and reinitialise query q when function test is called the second time, but apparenty my code is wrong and both instances of query q continue to run.

    Your help is much appreciated, thank you.

  • Stéphane Bruckert
    Stéphane Bruckert over 8 years
    Should this code stop test(1) when test(2) is ran? Because it doesn't stop it.
  • Parag Bafna
    Parag Bafna over 6 years
    It will crash on latest os. Release of a suspended object
  • Vikas Dadheech
    Vikas Dadheech almost 3 years
    can i get a swift version of this? :)