web-dev-qa-db-fra.com

Suspension du problème de requête GCD

j'ai du mal à suspendre une requête gcd. Voici du code qui illustre le problème:

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;
}

Ce que j'essaie de faire est de suspendre, de libérer et de réinitialiser la requête q lorsque le test de fonction est appelé la deuxième fois, mais apparemment, mon code est incorrect et les deux instances de la requête q continuent de s'exécuter.

Votre aide est très appréciée, merci.

30
Kostas.N

Tous les blocs qui ont été envoyés de manière asynchrone dans votre file d'attente avant d'appeler réellement dispatch_suspend () seront exécutés avant que la suspension ne prenne effet. Dans votre code, vous lancez un tas de blocs de manière asynchrone, donc certains sont probablement encore dans la file d'attente lorsque vous appelez test (2), et ces blocs seront exécutés.

Si vous souhaitez pouvoir annuler vos travaux en cours, vous devrez le faire dans votre propre logique. GCD n'expose pas délibérément une véritable API d'annulation. Vous pouvez faire quelque chose comme ça:

@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);}
    });

}

De cette façon, chaque bloc gardera une référence à un objet qui sait s'il doit cesser de fonctionner.

41
Ryan

De Apple Référence GCD :

dispatch_suspend

En suspendant un objet de répartition, votre application peut temporairement empêcher l'exécution de tout bloc associé à cet objet. La suspension se produit après l'achèvement de tous les blocs en cours d'exécution au moment de l'appel . L'appel de cette fonction incrémente le nombre de suspensions de l'objet et l'appel à dispatch_resume le diminue. Bien que le nombre soit supérieur à zéro, l'objet reste suspendu, vous devez donc équilibrer chaque appel dispatch_suspend avec un appel dispatch_resume correspondant.

[mine audacieuse]

Je suppose que c'est le cas car lorsqu'un bloc est exécuté, il quitte la file d'attente. Il semble donc que vous ne puissiez pas suspendre un bloc déjà en cours d'exécution.

5
sergio