2011-07-18 86 views
27

我無法掛起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時,功能測試被稱爲第二次,但apparenty我的代碼是錯誤的,的兩個實例查詢q繼續運行。

非常感謝您的幫助,謝謝。

+0

你可能想[使用'NSOperationQueue'代替](http://stackoverflow.com/a/32807804/199360)。 – adib

回答

39

在實際調用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);} 
    }); 

} 

這樣,每塊將保持一個參考,它知道它是否應該停止做工作的對象。

+0

這樣做,謝謝 –

+0

當'test(2)'運行時,這段代碼應該停止'test(1)'嗎?因爲它不會阻止它。 –

+0

它會在最新的操作系統上崩潰。釋放一個懸浮物體 –

5

從蘋果GCD Reference

dispatch_suspend

通過暫停調度對象,應用程序可以暫時阻止與該對象有關的任何塊的執行。 在呼叫時運行的任何程序段完成後發生暫停。調用這個函數會增加對象的暫停計數,並調用dispatch_resume來減少它。雖然計數大於零,但對象仍處於暫停狀態,因此您必須將每個dispatch_suspend調用與匹配的dispatch_resume調用進行平衡。

[粗體礦]

我假定這是因爲在執行一個塊時,它離開隊列。所以,看起來你不能暫停已經執行的程序段。