Using Grand Central Dispatch outside of an application or runloop

You don't need to call anything to start the dispatcher, but you can't exit the main thread or your program will exit even if there is incomplete work on queues. You can prevent the main thread from exiting by using semaphores:

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

Instead of semaphores, there's the conceptually easier but less useable approach of calling sleep, or counting to a huge number in a loop (make sure the compiler doesn't optimize it away), or looping until a variable (initially set to false, set to true when processing is done) is true (known as a busy-wait). Each of these has severe deficiencies and is far less preferable than a semaphore.

You can also test it by making a serial queue and calling dispatch_async on it a few times, then dispatch_sync, then exiting the program.

There are good reasons to call dispatch_main or start a run loop, but be aware things you send to any queue except the main queue can start BEFORE the runloop to dispatch_main is started.


No, you don't need any additional setup. But you need to call dispatch_main() to start the GCD dispatcher.
As dispatch_main() never returns, this will also prevent your main function from reaching it's return.

Example for a minimal C program that uses GCD & a global queue (based on 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);
}

To compile this, use:

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