2011-07-18 13 views
27

tengo problemas para suspender una consulta gcd. Aquí hay un código que muestra el problema:Suspendiendo problema de consulta 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; 
} 

Lo que estoy tratando de hacer es suspender, liberación y reinicializar consulta q cuando las pruebas de función se llama la segunda vez, pero apparenty mi código es incorrecto y las dos instancias de consulta q continuar ejecutando.

Su ayuda es muy apreciada, gracias.

+0

Es posible que desee [use 'NSOperationQueue' en su lugar] (http://stackoverflow.com/a/32807804/199360). – adib

Respuesta

39

Cualquier bloque que se haya enviado a su cola de forma asincrónica antes de llamar realmente 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. Se podría 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 debe dejar de hacer el trabajo.

+0

Esto hace el truco, gracias –

+0

¿Debería este código detener 'test (1)' cuando se ejecuta 'test (2)'? Porque no lo detiene. –

+0

Se bloqueará en el último sistema operativo. Lanzamiento de un objeto suspendido –

5

de Apple GCD Reference:

dispatch_suspend

Al suspender un objeto de despacho, la aplicación puede impedir temporalmente la ejecución de los bloques asociados 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.

[negrita mía]

Asumo que esto es así porque cuando se ejecuta un bloque, que sale de la cola. Entonces, parece que no puedes suspender un bloque que ya está en ejecución.

Cuestiones relacionadas