Использование Grand Central Dispatch вне приложения или runloop - PullRequest
7 голосов
/ 03 декабря 2011

В документации GCD совершенно ясно, что для отправки работы в основную очередь вам нужно либо работать внутри NSApplication (или UIApplication), либо вызывать dispatch_main (), чтобы действовать как своего рода цикл выполнения.Однако нужно ли мне что-то делать для настройки глобальной параллельной очереди?

По сути, я спрашиваю следующее: если я пишу простую простую C-программу, нужно ли мне выполнять какую-либо специальную настройку, прежде чем я отправлю dispatch_get_global_queue () и начать давать ему работу?

Ответы [ 2 ]

7 голосов
/ 03 декабря 2011

Вам не нужно ничего вызывать, чтобы запустить диспетчер, но вы не можете выйти из основного потока, иначе ваша программа завершит работу, если работа с очередями будет неполной. Вы можете предотвратить выход из основного потока, используя семафоры:

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

Вместо семафоров, есть концептуально более простой, но менее полезный подход вызова сна или подсчета до огромного числа в цикле (убедитесь, что компилятор не оптимизирует его), или циклического преобразования до переменной (первоначально установленной в false, устанавливается в true, когда обработка завершена) - true (известно как busy-wait ). Каждый из них имеет серьезные недостатки и гораздо менее предпочтителен, чем семафор.

Вы также можете проверить его, создав последовательную очередь и несколько раз вызвав для нее dispatch_async, затем dispatch_sync и выход из программы.

Существуют веские причины для вызова dispatch_main или запуска цикла выполнения, но имейте в виду, что вещи, которые вы отправляете в любую очередь, кроме главной, могут запускаться ДО запуск цикла запуска dispatch_main.

5 голосов
/ 03 декабря 2011

Нет, вам не нужно никаких дополнительных настроек. Но вам нужно вызвать dispatch_main () для запуска диспетчера GCD.
Так как dispatch_main () никогда не возвращается, это также не даст вашей основной функции достичь своего возврата.

Пример для программы на минимальном C, которая использует GCD и глобальную очередь (на основе 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);
}

Для компиляции используйте:

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