Подтвердить что ты не робот

Приостановка проблемы запроса GCD

У меня есть проблема с приостановлением запроса 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 продолжают работать.

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

4b9b3361

Ответ 1

Любые блоки, которые были отправлены в вашу очередь асинхронно, прежде чем вы на самом деле вызовите 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);}
    });

}

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

Ответ 2

Из Apple Ссылка GCD:

dispatch_suspend

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

[смелый мины]

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