2011-12-03 9 views
7

W dokumentacji GCD jest całkiem jasne, że aby przesłać pracę do głównej kolejki, musisz działać w ramach aplikacji NSApplication (lub UIApplication) lub wywołać metodę dispatch_main(), aby działała jako uruchomienie sortowania. Jednak czy muszę zrobić wszystko, aby skonfigurować globalną kolejkę współbieżną?Używanie Grand Central Dispatch poza aplikacją lub runloop

Zasadniczo o to pytam: jeśli piszę prosty prosty program w języku C, czy muszę przeprowadzić jakąś konfigurację specjalną zanim przejdę do funkcji dispatch_get_global_queue() i zacznę ją zatwierdzać?

Odpowiedz

4

Nie, nie potrzebujesz żadnych dodatkowych ustawień. Ale musisz wywołać metodę dispatch_main(), aby uruchomić program rozsyłający GCD.
Jako, że funkcja dispatch_main() nigdy nie wraca, uniemożliwi to Twojej głównej funkcji osiągnięcie zwrotu.

Przykład minimalnym C programu, który używa GCD & kolejkę globalnej (na podstawie 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); 
} 

Aby skompilować ten, przeznaczenie:

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

Nie potrzebujesz wywołania dispatch_main. Jeśli zastąpisz go 10-sekundowym trybem uśpienia, na przykład 5-sekundowy czasomierz nadal będzie wyzwalać. – Stripes

7

Nie trzeba zadzwonić cokolwiek, aby uruchomić program rozsyłający, ale nie można wyjść z głównego wątku lub program zostanie zamknięty, jeśli w kolejce nie ma jeszcze pracy. Można zapobiec główny wątek z opuszczeniem przez wykorzystaniem semaforów:

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; 
} 

Zamiast semaforów, nie jest koncepcyjnie prostsze, ale mniej użyteczne podejście wywoływania snu, lub licząc na ogromną liczbę w pętli (upewnij się, że kompilator nie robi zoptymalizować go) lub zapętlić, aż zmienna (początkowo ustawiona na wartość false, ustawiona na true, gdy przetwarzanie zostanie wykonane) jest prawdziwa (znana jako busy-wait). Każdy z nich ma poważne braki i jest znacznie mniej preferowany niż semafor.

Można również przetestować go, tworząc kolejkę szeregową i wywołując na niej metodę dispatch_async kilka razy, a następnie dispatch_sync, a następnie opuszczając program.

Istnieją powody, aby wywoływać metodę dispatch_main lub uruchamiać pętlę uruchamiania, ale należy pamiętać, że przesyłane są do dowolnej kolejki z wyjątkiem głównej kolejki, która może się rozpocząć PRZED uruchomiono uruchomienie do dispatch_main.

+0

Jest to również dobra odpowiedź na pytanie "Jak zamknąć wdzięcznie program oparty na libdispatch". Odnotowany do późniejszego odniesienia. – Eonil

+1

Ten wymaga ręcznego liczenia "zadań kolejkowania". Czy istnieje sposób na zakończenie dispatch_main(), gdy wszystkie kolejki są wyczerpane/i nie ma przypisanych dispatch_source? Podobny do NSRunLoop (który AFAIK właśnie kończy -run, jeśli nie pozostało nic do uruchomienia). – hnh

+1

Nie, najbliżej mogę myśleć o użyciu wszystkich dispatch_group_async do rozpoczęcia pracy, a następnie za pomocą dispatch_group_notify, aby uruchomić wyjście, ale to nie jest ogólne ani automatyczne. Może coś z rozpoczęciem całej pracy, dodając obsługę dealloc do kolejki i zwalniania ich, ale to ma problemy z wskrzeszeniem. Myślę, że twoja aplikacja musi z natury wiedzieć, jak rozpoznać kompletność, ekspedycja może pomóc w propagowaniu tej wiadomości, ale nie może jej powstać. – Stripes

Powiązane problemy