Приостановка проблемы запроса GCD - PullRequest
30 голосов
/ 18 июля 2011

У меня проблемы с приостановкой gcd-запроса. Вот некоторый код, который демонстрирует проблему:

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

Я пытаюсь приостановить, отпустить и повторно инициализировать запрос q, когда функциональный тест вызывается во второй раз, но очевидно, что мой код неверен, и оба экземпляра запроса q продолжают выполняться.

Ваша помощь очень ценится, спасибо.

Ответы [ 2 ]

41 голосов
/ 18 июля 2011

Любые блоки, которые были асинхронно отправлены в вашу очередь, прежде чем вы на самом деле вызовите dispatch_suspend (), будут запущены до того, как приостановка вступит в силу. В вашем коде вы запускаете несколько блоков асинхронно, поэтому некоторые из них, вероятно, все еще находятся в очереди, когда вы вызываете test (2), и эти блоки будут выполнены.

Если вы хотите отменить выполняемые задания, вам нужно сделать это в соответствии с вашей собственной логикой. GCD целенаправленно не предоставляет истинного API отмены. Вы могли бы сделать что-то вроде этого:

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

}

Таким образом, каждый блок будет хранить ссылку на объект, который знает, должен ли он прекратить работу.

5 голосов
/ 18 июля 2011

От Apple GCD Reference :

dispatch_suspend

Приостановив объект отправки, ваше приложение может временно запретить выполнение любых блоков, связанных с этим объектом, Приостановка происходит после завершения любых блоков, работающих на момент вызова .Вызов этой функции увеличивает счетчик приостановки объекта, а вызов dispatch_resume уменьшает его.Хотя число больше нуля, объект остается приостановленным, поэтому вы должны балансировать каждый вызов dispatch_suspend с соответствующим вызовом dispatch_resume.

[жирный шрифт]

Я предполагаю, что этопотому что, когда блок выполняется, он покидает очередь.Похоже, вы не можете приостановить блок, уже запущенный.

...