2011-12-21 9 views
14

Tengo un objeto NSRunLoop, al que adjunto temporizadores y transmisiones. Funciona muy bien. Detenerlo es otra historia en conjunto.CFRunLoopRun() vs [ejecución de NSRunLoop]

Ejecuto el ciclo usando [runLoop run].

Si trato de detener el ciclo con CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]), el ciclo no se detiene. Si comienzo el ciclo usando CRunLoopRun(), funciona. También me he asegurado de que la llamada se realice en el hilo correcto (el que ejecuta mi ciclo de ejecución personalizado). Lo he depurado con pthread_self().

Encontré un archivo de la lista de correo, donde un desarrollador dijo "no se moleste en usar CRunLoopStop() si comenzó el ciclo con el método de ejecución NSRunLoop". Puedo entender por qué es así: normalmente empareja inicializadores y finalizadores del mismo conjunto de funciones.

¿Cómo se detiene un NSRunLoop sin "recurrir a CF"? No veo un método stop en NSRunLoop. La documentación dice que puede detener un bucle de ejecución de tres maneras:

  1. Configurar el bucle de ensayo a ensayo con un valor de tiempo de espera
  2. Informe a todo el bucle de ejecución a dejar de usar CFRunLoopStop()
  3. Eliminar todas las fuentes de entrada, pero esta es una manera poco fiable para detener el bucle de ejecución porque nunca se puede saber lo metió lo que en el plazo de bucle detrás de la espalda

Bueno, yo ya probé 2. y hay un "feo" se siente, porque tiene que profundizar en CF. 3. está fuera de discusión - No me gusta el código no determinista.

Esto nos deja con 1. Si entiendo los documentos correctamente, no puede "agregar" un tiempo de espera a un ciclo de ejecución ya existente. Solo puede ejecutar nuevos bucles de ejecución con un tiempo de espera excedido. Si ejecuto un nuevo ciclo de ejecución, no resolverá mi problema, ya que solo creará un ciclo de ejecución anidado. Todavía voy a volver a aparecer en el anterior, lo mismo que quería dejar ... ¿verdad? Pude haber entendido mal este. Además, no quiero ejecutar el ciclo con un valor de tiempo de espera excedido. Si lo hago, tendré que hacer una transacción entre grabar ciclos de CPU (valor de tiempo de espera bajo) y capacidad de respuesta (valor de tiempo de espera alto).

Esta es la configuración que tengo ahora (pseudo código-ish):

Communicator.h

@interface Communicator : NSObject { 
    NSThread* commThread; 
} 

-(void) start; 
-(void) stop; 
@end 

Communicator.m

@interface Communicator (private) 
-(void) threadLoop:(id) argument; 
-(void) stopThread; 
@end 

@implementation Communicator 
-(void) start { 
    thread = [[NSThread alloc] initWithTarget:self 
            selector:@selector(threadLoop:) 
             object:nil]; 
    [thread start]; 
} 

-(void) stop { 
    [self performSelector:@selector(stopThread) 
       onThread:thread 
       withObject:self 
      waitUntilDone:NO]; 
    // Code ommitted for waiting for the thread to exit... 
    [thread release]; 
    thread = nil; 
} 
@end 

@implementation Communicator (private) 
-(void) stopThread { 
    CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]); 
} 

-(void) threadLoop:(id) argument { 
    // Code ommitted for setting up auto release pool 

    NSRunLoop* runLoop = [NSRunLoop currentRunLoop]; 

    // Code omitted for adding input sources to the run loop 

    CFRunLoopRun(); 
    // [runLoop run]; <- not stoppable with 

    // Code omitted for draining auto release pools 

    // Code omitted for signalling that the thread has exited 
} 
@endif 

¿Qué soy yo ¿que hacer? ¿Es común/un buen patrón perder el tiempo con CF? No sé Fundación lo suficientemente bien. ¿Es posible que la interferencia en la capa de CF sea peligrosa (con respecto a la corrupción de la memoria, inconsistencias, pérdidas de memoria)? ¿Hay un patrón mejor para lograr lo que estoy tratando de lograr?

Respuesta

7

Te va bien. No hay problema para usar CoreFoundation cuando no puede lograr su objetivo con Foundation. Como CoreFoundation es C, es más fácil estropear la administración de la memoria, pero no existe un peligro intrínseco al usar CFRunLoop en lugar de NSRunLoop (sometimes it may even be safer: CFRunLoop API son seguros para subprocesos mientras que NSRunLoop no lo está).

Si quiere detener su NSRunLoop, puede ejecutarlo usando runMode:beforeDate:. runMode:beforeDate: regresa tan pronto como se procese una fuente de entrada, por lo que no necesita esperar hasta que se llegue a la fecha límite.

NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
NSDate *date = [NSDate distantFuture]; 
while (!runLoopIsStopped && [runLoop runMode:NSDefaultRunLoopMode beforeDate:date]); 

Entonces, para detener el bucle de ejecución, sólo tiene que ajustar a runLoopIsStoppedYES.

+0

¡Ah, listo! No vi que 'runMode' se ejecutara solo una vez. ¿Se incurre en una penalización de rendimiento significativa al iniciar el ciclo de ejecución una y otra vez? –

+0

No, no lo hay: así es como funcionan '- [Ejecutar NSRunLoop]' y '- [Ejecutar NSRunLoop:]'. –

+1

El hilo no se detendrá si acaba de establecer runLoopIsStopped en SÍ. Tiene que establecerlo en SÍ y realizar una acción en el hilo de ese ciclo de ejecución, de lo contrario el [modo de ejecución de RunLoop: ModoDeInicioRunLoop beforeDate: fecha] no saldrá. Esto me llevó años descubrirlo. – Pada

Cuestiones relacionadas