objective-c - tutorial - nsoperationqueue swift 3 example
Suspendiendo problema de consulta GCD (2)
Tengo problemas para suspender una consulta gcd. Aquí hay un código que demuestra el problema:
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;
}
Lo que trato de hacer es suspender, liberar y reiniciar la consulta q cuando se llama a la prueba de función por segunda vez, pero aparentemente mi código es incorrecto y ambas instancias de consulta q continúan ejecutándose.
Su ayuda es muy apreciada, gracias.
Cualquier bloque que haya sido enviado a su cola de manera asincrónica antes de que realmente llame a dispatch_suspend () se ejecutará antes de que la suspensión surta efecto. En su código está disparando un grupo de bloques de forma asíncrona, por lo que algunos probablemente todavía estén en la cola cuando llame a prueba (2), y esos bloques se ejecutarán.
Si desea poder cancelar sus trabajos en ejecución, tendrá que hacerlo en su propia lógica. GCD a propósito no expone una verdadera API de cancelación. Podrías hacer algo como esto:
@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);}
});
}
De esta forma, cada bloque mantendrá una referencia a un objeto que sabe si debería dejar de funcionar.
De Apple GCD Referencia :
dispatch_suspend
Al suspender un objeto de envío, su aplicación puede evitar temporalmente la ejecución de cualquier bloque asociado con ese objeto. La suspensión se produce después de la finalización de cualquier bloqueo que se ejecute en el momento de la llamada . Al llamar a esta función, aumenta el recuento de suspensiones del objeto y al llamar a dispatch_resume se lo disminuye. Si bien el recuento es mayor que cero, el objeto permanece suspendido, por lo que debe equilibrar cada llamada dispatch_suspen con una llamada dispatch_resume correspondiente.
[bold mine]
Supongo que esto es así porque cuando se ejecuta un bloque, sale de la cola. Entonces, parece que no puedes suspender un bloque que ya está en ejecución.