1.\" Copyright (c) 2008-2010 Apple Inc. All rights reserved. 2.Dd May 1, 2009 3.Dt dispatch_apply 3 4.Os Darwin 5.Sh NAME 6.Nm dispatch_apply 7.Nd schedule blocks for iterative execution 8.Sh SYNOPSIS 9.Fd #include <dispatch/dispatch.h> 10.Ft void 11.Fo dispatch_apply 12.Fa "size_t iterations" "dispatch_queue_t queue" "void (^block)(size_t)" 13.Fc 14.Ft void 15.Fo dispatch_apply_f 16.Fa "size_t iterations" "dispatch_queue_t queue" "void *context" "void (*function)(void *, size_t)" 17.Fc 18.Sh DESCRIPTION 19The 20.Fn dispatch_apply 21function provides data-level concurrency through a "for (;;)" loop like primitive: 22.Bd -literal 23dispatch_queue_t the_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 24size_t iterations = 10; 25 26// 'idx' is zero indexed, just like: 27// for (idx = 0; idx < iterations; idx++) 28 29dispatch_apply(iterations, the_queue, ^(size_t idx) { 30 printf("%zu\\n", idx); 31}); 32.Ed 33.Pp 34Like a "for (;;)" loop, the 35.Fn dispatch_apply 36function is synchronous. 37If asynchronous behavior is desired, please wrap the call to 38.Fn dispatch_apply 39with a call to 40.Fn dispatch_async 41against another queue. 42.Pp 43Sometimes, when the block passed to 44.Fn dispatch_apply 45is simple, the use of striding can tune performance. 46Calculating the optimal stride is best left to experimentation. 47Start with a stride of one and work upwards until the desired performance is 48achieved (perhaps using a power of two search): 49.Bd -literal 50#define STRIDE 3 51 52dispatch_apply(count / STRIDE, queue, ^(size_t idx) { 53 size_t j = idx * STRIDE; 54 size_t j_stop = j + STRIDE; 55 do { 56 printf("%zu\\n", j++); 57 } while (j < j_stop); 58}); 59 60size_t i; 61for (i = count - (count % STRIDE); i < count; i++) { 62 printf("%zu\\n", i); 63} 64.Ed 65.Sh IMPLIED REFERENCES 66Synchronous functions within the dispatch framework hold an implied reference 67on the target queue. In other words, the synchronous function borrows the 68reference of the calling function (this is valid because the calling function 69is blocked waiting for the result of the synchronous function, and therefore 70cannot modify the reference count of the target queue until after the 71synchronous function has returned). 72.Pp 73This is in contrast to asynchronous functions which must retain both the block 74and target queue for the duration of the asynchronous operation (as the calling 75function may immediately release its interest in these objects). 76.Sh FUNDAMENTALS 77Conceptually, 78.Fn dispatch_apply 79is a convenient wrapper around 80.Fn dispatch_async 81and a semaphore to wait for completion. 82In practice, the dispatch library optimizes this function. 83.Pp 84The 85.Fn dispatch_apply 86function is a wrapper around 87.Fn dispatch_apply_f . 88.Sh CAVEATS 89Unlike 90.Fn dispatch_async , 91a block submitted to 92.Fn dispatch_apply 93is expected to be either independent or dependent 94.Em only 95on work already performed in lower-indexed invocations of the block. If 96the block's index dependency is non-linear, it is recommended to 97use a for-loop around invocations of 98.Fn dispatch_async . 99.Sh SEE ALSO 100.Xr dispatch 3 , 101.Xr dispatch_async 3 , 102.Xr dispatch_queue_create 3 , 103.Xr dispatch_semaphore_create 3 104