暂停GCD查询问题

时间:2011-07-18 17:48:14

标签: objective-c grand-central-dispatch

我无法暂停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 个答案:

答案 0 :(得分:41)

在实际调用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);}
    });

}

通过这种方式,每个块将保持对一个对象的引用,该对象知道它是否应该停止工作。

答案 1 :(得分:5)

来自Apple GCD Reference

  

dispatch_suspend

     

通过挂起调度对象,您的应用程序可以暂时阻止执行与该对象关联的任何块。 在完成通话时运行的任何阻止后发生暂停。调用此函数会增加对象的暂停计数,并调用dispatch_resume会减少它。当计数大于零时,对象保持挂起状态,因此您必须使用匹配的dispatch_resume调用平衡每个dispatch_suspend调用。

[大胆的雷]

我认为这是因为当执行一个块时,它会离开队列。所以,似乎你不能暂停已经执行的块。