Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Grand Central Dispatch outside of an application or runloop

In the GCD documentation it's quite clear that to submit work to the main queue, you need to either be working within an NSApplication (or UIApplication) or call dispatch_main() to act as a run loop of sorts. However, do I need to do anything to setup the global concurrent queue?

Basically what I am asking is: If I write a plain simple C program, do I need to perform any special setup before I go dispatch_get_global_queue() and start giving it work?

like image 565
dented42 Avatar asked Dec 03 '11 07:12

dented42


People also ask

How does Grand Central Dispatch work?

GCD is built on top of threads. Under the hood, it manages a shared thread pool. With GCD, you add blocks of code or work items to dispatch queues and GCD decides which thread to execute them on. As you structure your code, you'll find code blocks that can run simultaneously and some that should not.

What is Grand Central Dispatch iOS?

Dispatch, also known as Grand Central Dispatch (GCD), contains language features, runtime libraries, and system enhancements that provide systemic, comprehensive improvements to the support for concurrent code execution on multicore hardware in macOS, iOS, watchOS, and tvOS.

What is global queue Swift?

Global queues: concurrent queues that are shared by the whole system. There are four such queues with different priorities : high, default, low, and background. The background priority queue has the lowest priority and is throttled in any I/O activity to minimize negative system impact.

How many types of queues are there in Swift?

There are two types of dispatch queues, serial dispatch queues and concurrent dispatch queues. It's easy to understand the difference. A serial queue executes the commands it's given in a predictable order.


2 Answers

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.

like image 193
Stripes Avatar answered Sep 22 '22 05:09

Stripes


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
like image 42
Thomas Zoechling Avatar answered Sep 23 '22 05:09

Thomas Zoechling