2011-12-03 17 views
7

En la documentación de GCD, es bastante claro que para enviar trabajo a la cola principal, debe estar trabajando dentro de una aplicación NSA (o aplicación UIA) o llamar a dispatch_main() para actuar como un bucle de ejecución de tipo. Sin embargo, ¿tengo que hacer algo para configurar la cola concurrente global?Uso de Grand Central Dispatch fuera de una aplicación o runloop

Básicamente lo que estoy preguntando es: Si escribo un programa C sencillo, ¿necesito realizar alguna configuración especial antes de ir a dispatch_get_global_queue() y comenzar a darle trabajo?

Respuesta

4

No, no necesita ninguna configuración adicional. Pero necesita llamar a dispatch_main() para iniciar el despachador de GCD.
Como dispatch_main() nunca regresa, esto también evitará que su función principal llegue a su devolución.

Ejemplo para un programa mínimo que utiliza C GCD & una cola mundial (basado en http://wiki.freebsd.org/GCD):

#include <dispatch/dispatch.h> 
#include <err.h> 
#include <stdio.h> 
#include <stdlib.h> 

int main(int argc, char *argv[]) 
{ 
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_time_t dispatchTime = dispatch_time(DISPATCH_TIME_NOW, 5LL * NSEC_PER_SEC); 
    dispatch_after(dispatchTime, globalQueue, ^{ 
     printf("Dispatched on global queue\n"); 
     exit(0); 
    }); 
    dispatch_main(); 
    return (0); 
} 

Para recopilar la información, uso:

clang -Wall -Werror -fblocks -L/usr/local/lib -I/usr/local/include -o test test.c 
+1

No necesita la llamada dispatch_main. Si lo reemplaza con un descanso de 10 segundos, por ejemplo, ese temporizador de 5 segundos aún se disparará. – Stripes

7

que no es necesario llamar cualquier cosa para iniciar el despachador, pero no puede salir del hilo principal o su programa se cerrará si hay trabajo incompleto en las colas. Puede evitar que el flujo principal que sale mediante el uso de semáforos:

int main() { 
    __block int count = 10; 
    dispatch_semaphore_t done = dispatch_semaphore_create(0); 
    dispatch_time_t naptime; 

    // timeout after 5 seconds 
    naptime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)5E9); 
    // no timeout 
    //naptime = dispatch_time(DISPATCH_TIME_FOREVER, 0); 

    // schedule some work 
    dispatch_async(
     dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), 
     ^{ 
      dispatch_apply(count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0), 
       ^(size_t i){ 
        //... 
        // note: potential race condition on count. 
        // Synchronization left as an exercise. 
        if (--count == 0) { 
         dispatch_semaphore_signal(done); 
        } 
       } 
      ); 
     } 
    ); 

    if (dispatch_semaphore_wait(done, naptime)) { 
     // processing didn't complete in allotted time 
     //... 
    } 
dispatch_release(done); 
    return 0; 
} 

En vez de semáforos, está el enfoque conceptualmente más fácil pero menos útil de llamar el sueño, o contar hasta un número enorme en un bucle (asegúrese de que el compilador doesn lo optimice), o bucle hasta que una variable (inicialmente establecida en falso, establecida en verdadero cuando se realiza el procesamiento) sea verdadera (conocida como busy-wait). Cada uno de estos tiene graves deficiencias y es mucho menos preferible que un semáforo.

También puede probar haciendo una cola en serie y llamando a dispatch_async varias veces, luego dispatch_sync y luego saliendo del programa.

Existen buenas razones para llamar dispatch_main o iniciar un bucle de ejecución, pero ser conscientes de las cosas que envíe a cualquier cola, excepto la cola principal puede comenzar antes la runloop a dispatch_main se ha iniciado.

+0

Esta es también una buena respuesta para la pregunta "Cómo cerrar con gracia el programa basado en libdispatch". Tomó nota para referencia posterior. – Eonil

+1

Esto requiere el recuento manual de 'trabajos de cola'. ¿Hay alguna manera de terminar dispatch_main() cuando todas las colas están agotadas/y no tienen asignados dispatch_source? Similar a NSRunLoop (que AFAIK acaba de ejecutar -ejecutar si no queda nada por ejecutar). – hnh

+1

No, lo más cercano que puedo pensar es usar todo dispatch_group_async para comenzar a trabajar y luego usar dispatch_group_notify para activar la salida, pero eso no es general ni automático. Tal vez algo con comenzar todo el trabajo agregando manejadores de dealloc a las colas y soltándolos, pero eso tiene problemas de resurrección ilegales. Creo que su aplicación debe saber inherentemente cómo reconocer la integridad, el envío puede ayudar a propagar ese mensaje, pero no puede originarlo. – Stripes

Cuestiones relacionadas