Приостановка проблемы запроса 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 продолжают работать.
Ваша помощь очень ценится, спасибо.
Ответы
Ответ 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.
[смелый мины]
Я предполагаю, что это происходит потому, что, когда выполняется блок, он покидает очередь. Таким образом, кажется, что вы не можете приостановить блок, уже исполняемый.