-
-
Notifications
You must be signed in to change notification settings - Fork 6
Grand Central Dispatch
MidnightBSD includes the libdispatch library along with some kernel changes from FreeBSD to support GCD features.
GCD was ported to FreeBSD by Robert Watson and Stacey Son. See http://people.freebsd.org/~sson/thrworkq/
MidnightBSD has supported GCD/libdispatch features for some time. Support was greatly improved in MidnightBSD 1.0. Prior to that, there were edge cases in the 0.8.x line that would cause stalls.
The system compiler supports blocks in MidnightBSD 1.0 or higher as it's LLVM clang with compiler_rt.
Note: this documentation is based on the FreeBSD wiki page https://wiki.freebsd.org/action/show/GrandCentralDispatch?action=show&redirect=GCD
Below you'll find some same programs to try out libdispatch. It's recommended to look at the various man pages. In addition, there is currently one app in the MidnightBSD base system using libdispatch, the package manager. Look at libmport for another example of usage.
With Blocks
#include <dispatch/dispatch.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
dispatch_queue_t q;
dispatch_time_t t;
`q = dispatch_get_main_queue(); `
`t = dispatch_time(DISPATCH_TIME_NOW, 5LL * NSEC_PER_SEC); // Print a message and exit after 5 seconds. `
`dispatch_after(t, q, ^{ printf("block_dispatch\n"); exit(0); }); `
`dispatch_main(); `
`return (0);`
}
Compile with:
clang -Wall -Werror -fblocks -o test test.c -ldispatch
Without Blocks
#include <dispatch/dispatch.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
void
deferred_code(__unused void *arg)
{
`printf("block_dispatch\n");`
`exit(0);`
}
int
main(int argc, char *argv[])
{
dispatch_queue_t q;
dispatch_time_t t;
`q = dispatch_get_main_queue();`
`t = dispatch_time(DISPATCH_TIME_NOW, 5LL * NSEC_PER_SEC);`
`dispatch_after_f(t, q, NULL, deferred_code);`
`dispatch_main();`
`return (0);`
}
Compile with:
gcc -Wall -Werror -o test2 test2.c -ldispatch
Time Based Scheduling
#include <dispatch/dispatch.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
void work(void *context __attribute__((unused)))
{
`struct timeval now;`
`intptr_t n = (intptr_t)context;`
`gettimeofday(&now, NULL);`
`printf("[%lu.%lu] starting work #%zd\n", now.tv_sec, now.tv_usec, n);`
`sleep(2);`
`gettimeofday(&now, NULL);`
`printf("[%lu.%lu] finished work #%zd\n", now.tv_sec, now.tv_usec, n);`
}
int main(void)
{
#if 1
dispatch_queue_t dispatch_q = dispatch_get_global_queue(0, 0);
#else
dispatch_queue_t dispatch_q = dispatch_get_main_queue();
#endif
`printf("=====> before dispatching jobs <=====\n");`
`dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_q, (void *)1, work);`
`dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_q, (void *)2, work);`
`printf("=====> after dispatching jobs <=====\n");`
`dispatch_main();`
`return 0;`
}
#include <unistd.h>
#include <stdio.h>
void work(void *context __attribute__((unused)))
{
`struct timeval now;`
`intptr_t n = (intptr_t)context;`
`gettimeofday(&now, NULL);`
`printf("[%lu.%lu] starting work #%zd\n", now.tv_sec, now.tv_usec, n);`
`sleep(2);`
`gettimeofday(&now, NULL);`
`printf("[%lu.%lu] finished work #%zd\n", now.tv_sec, now.tv_usec, n);`
}
int main(void)
{
#if 1
dispatch_queue_t dispatch_q = dispatch_get_global_queue(0, 0);
#else
dispatch_queue_t dispatch_q = dispatch_get_main_queue();
#endif
`printf("=====> before dispatching jobs <=====\n");`
`dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_q, (void *)1, work);`
`dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_q, (void *)2, work);`
`printf("=====> after dispatching jobs <=====\n");`
`dispatch_main();`
`return 0;`
}
Nested Steps
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <dispatch/dispatch.h>
#define STEPS 90000000
long num_steps = STEPS;
double step = 0;
// used to count how many steps are left
int stepsLeft = STEPS-1;
int main() {
__block double sum=0.0;
__block double pi = 0; // modifier is needed so blocks can write values to it
`// we can use the main queue instead of a newly created serialised queue, because the main queue is otherwise idle`
`// also works with a serialsed queue`
`dispatch_queue_t mainQueue = dispatch_get_main_queue();`
`// global queue is used to execute concurrently`
`dispatch_queue_t aQueue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);`
`// execute the loop`
`dispatch_apply ((num_steps-1), aQueue, ^ (size_t i) {`
`step = 1.0/(double) num_steps;`
`double x = (i+0.5)*step;`
`// dispatch must be asynchronious otherwise this thread will stall before continuing`
`dispatch_async(mainQueue, ^{`
`sum = sum + 4.0/(1.0+x*x);`
`stepsLeft--;`
`// if all executions are done and processed, execute the final stuff`
`if (stepsLeft== 0) {`
`pi = step*sum;`
`printf("The value of pi is %f\n", step*sum);`
`exit(0);`
`}`
`});`
`});`
`// this call must be made in order to process blocks submitted to the main queue`
`dispatch_main();`
`return 0;`
}
libdispatch ships with informative man pages describing not just the API, but also how to structure programs around GCD.
April-September 2009 FreeBSD status report - Grand Central Dispatch port - status on the FreeBSD port of GCD
Mac OS X Forge - open source libdispatch home - libdispatch subversion repository and mailing lists
Grand Central Dispatch: Technology Brief - a white paper from Apple introducing GCD.
Mac OS X Reference Library: Concurrency Programming Guide - a guide to concurrent programming on Mac OS X, much of which also applies to FreeBSD with the GCD port installed.
Mac Dev Center: Grand Central Dispatch Reference - reference material on GCD from Apple.
Mac OS Reference Library: Dispatch_Samples - sample code using GCD from Apple.
20090918-devsummit-gcd-public.pdf - 2008 DevSummit Presentation