2011-07-18 6 views
27

gcdクエリを中断するのに問題があります。ここでは、問題を示し、いくつかのコードは次のとおりです。、解除と再初期化クエリQ機能テストが二度目に呼ばれているが、apparenty私のコードが間違っていると、両方のインスタンスの私は中断されてやろうとしている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は引き続き実行されます。

ご協力いただきありがとうございます。アップルGCD Referenceから

+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

最新のOSでクラッシュします。中断したオブジェクトの解放 –

5

:ディスパッチオブジェクトを懸濁させることにより

dispatch_suspend

を、あなたのアプリケーションは、一時的にそのオブジェクトに関連付けられたすべてのブロックの実行を防ぐことができます。 のコール時に実行中のブロックの完了後に中断が発生します。この関数を呼び出すと、オブジェクトのサスペンドカウントがインクリメントされ、dispatch_resumeを呼び出すとそれがデクリメントされます。カウントがゼロより大きい間、オブジェクトは中断されたままなので、各dispatch_suspendコールと対応するdispatch_resumeコールのバランスをとる必要があります。

[太字鉱山]

私はブロックが実行されると、それがキューを離れるので、これがそうであることを前提としています。したがって、実行中のブロックを中断することはできないようです。