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;
}
私がしようとしているのは、関数テストが2回目に呼び出されたときにクエリqを中断、解放、および再初期化することですが、コードが間違っているようで、クエリqの両方のインスタンスが引き続き実行されます。
よろしくお願いいたします。
実際に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);}
});
}
このようにして、各ブロックは、作業を停止する必要があるかどうかを認識するオブジェクトへの参照を保持します。
からApple GCD Reference :
dispatch_suspend
ディスパッチオブジェクトを一時停止することにより、アプリケーションはそのオブジェクトに関連付けられたブロックの実行を一時的に防ぐことができます。 一時停止は、呼び出し時に実行中のブロックが完了すると発生します。この関数を呼び出すと、オブジェクトの中断カウントが増加し、dispatch_resumeを呼び出すと、オブジェクトが減少します。カウントがゼロより大きい間、オブジェクトは中断されたままなので、各dispatch_suspend呼び出しと対応するdispatch_resume呼び出しのバランスをとる必要があります。
[大胆な鉱山]
これは、ブロックが実行されると、キューを離れるためです。したがって、すでに実行中のブロックを一時停止することはできないようです。