Slide 1

Slide 1 text

Gentle Introduction to Grand Central Dispatch Better to Remain Silent and Be Thought a Fool than to Speak and Remove All Doubt

Slide 2

Slide 2 text

Blocks • Topic unto themselves • Minimal info here • *async calls copy block • Blocks are true ObjC objects • All ObjC objects are retained when block is copied

Slide 3

Slide 3 text

Queues • Just a data structure (FIFO) • List of Blocks • enqueue • Atomic, lock-free • dequeue • Automatically handled by the “system”

Slide 4

Slide 4 text

Serial Queue enqueue dequeue

Slide 5

Slide 5 text

Concurrent Queue enqueue dequeue

Slide 6

Slide 6 text

Automatic Thread Management • Queues are not Threads! • Automatically creates threads as needed • Manages threads for concurrent queues based on processor utilization • Serial queues use overcommit queues • Can overwhelm system with blocks that pend for any reason

Slide 7

Slide 7 text

Global Queues • Concurrent • Based on Priority #define DISPATCH_QUEUE_PRIORITY_HIGH 2 #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 #define DISPATCH_QUEUE_PRIORITY_LOW (-2) #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN • dispatch_get_global_queue dispatch_queue_t dispatch_get_global_queue( long priority, unsigned long flags); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Slide 8

Slide 8 text

dispatch_queue_t • Obtain a global queue or main queue dispatch_queue_t dispatch_get_global_queue( long priority, unsigned long flags); dispatch_queue_t dispatch_get_main_queue(void); • Create a private queue dispatch_queue_t dispatch_queue_create( const char *label dispatch_queue_attr_t attr); • All private queues target a global queue • dispatch_retain/dispatch_release

Slide 9

Slide 9 text

dispatch_async • Puts block on queue, returns immediately • Block is copied to heap • Beware retain cycles • Execution is started in FIFO • Concurrent queues may not finish FIFO

Slide 10

Slide 10 text

dispatch_async • Must manually retain dispatch objects - (void)doSomethingThenInvokeBlock:(void(^)(void))block onQueue:(dispatch_queue_t)queue { dispatch_retain(queue); dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Do Something... dispatch_async(queue, block); dispatch_release(queue); }); } • Dispatch objects are ObjC objects in iOS 6 and Mountain Lion

Slide 11

Slide 11 text

dispatch_async • Handle all up to iOS6 / Mountain Lion #include #if OS_OBJECT_USE_OBJC static inline void wjhDispatchRetain(dispatch_queue_t queue) { } static inline void wjhDispatchRelease(dispatch_queue_t queue) { } #else static inline void wjhDispatchRetain(dispatch_queue_t queue) { dispatch_retain(queue); } static inline void wjhDispatchRelease(dispatch_queue_t queue) { dispatch_release(queue); } #endif

Slide 12

Slide 12 text

dispatch_async • If you are brave and want a quick compile #undef dispatch_retain #define dispatch_retain wjhDispatchRetain #undef dispatch_release #define dispatch_release wjhDispatchRelease

Slide 13

Slide 13 text

dispatch_async • With macros... - (void)doSomethingThenInvokeBlock:(void(^)(void))block onQueue:(dispatch_queue_t)queue { wjhDispatchRetain(queue); dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Do Something... dispatch_async(queue, block); wjhDispatchRelease(queue); }); }

Slide 14

Slide 14 text

dispatch_async • Do Not Block the Main Thread!!! • GCD easily allows all work to be off main thread • Execute code in main thread (UI) dispatch_async(queue, ^{ // Do Something dispatch_async(dispatch_get_main_queue(), ^{ // Running on main thread. Do UI stuff here. }); });

Slide 15

Slide 15 text

dispatch_async • Difference between these? dispatch_async(queue, ^{ // Do Something }); // Small window for other stuff to be put on queue dispatch_async(queue, ^{ // Do Something Else }); dispatch_async(queue, ^{ // Do Something // Next block not put on queue until this one executes dispatch_async(queue, ^{ // Do Something Else }); });

Slide 16

Slide 16 text

dispatch_sync • Dispatch block and wait for it to complete before returning dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Do Something }); // Do not get here until the above block has run to completion • Can be useful as general synchronization primitive • Pair with async for read/write operations

Slide 17

Slide 17 text

dispatch_sync • Can deadlock dispatch_sync(queue, ^{ // Do Something dispatch_sync(queue, ^{ // Causes deadlock. }); }); • Be cautious about using *sync API • Can run on calling thread

Slide 18

Slide 18 text

Suspend / Resume • All dispatch objects (including queues) can be suspended and resumed • Immediately after running block(s)

Slide 19

Slide 19 text

Retargeting Queues • Can change target of queue (barrier) • All dequeue operations run in context of target queue • “Cut in line” pattern lowPriorityQueue = dispatch_queue_create( "com.foo.low", DISPATCH_QUEUE_SERIAL); highPriorityQueue = dispatch_queue_create( "com.foo.high", DISPATCH_QUEUE_SERIAL); dispatch_set_target_queue(lowPriorityQueue, highPriorityQueue);

Slide 20

Slide 20 text

Cut in Line - (void)async:(void(^)(void))block { dispatch_async(lowPriorityQueue, block); } - (void)asyncHighPriority:(void(^)(void))block { dispatch_suspend(lowPriorityQueue); dispatch_async(highPriorityQueue, ^{ block(); dispatch_resume(lowPriorityQueue); }); } • What if did same without retargeting?

Slide 21

Slide 21 text

Change Priority • Change queue to high priority dispatch_set_target_queue( queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)); • Happens after current queue drains

Slide 22

Slide 22 text

Barrier Blocks • For concurrent queues (not global queues) • Waits for all enqueued blocks to execute • Only block executing on concurrent queue • Synchronizing concurrent operations • Reader/Writer locks

Slide 23

Slide 23 text

Reader/Writer Locks - (void)withReadAccess:(void(^)(void))block { dispatch_sync(queue_, block); } - (void)withWriteAccess:(void(^)(void))block { dispatch_barrier_async(queue_, block); } • Multiple threads executing read block • One thread executing write block • Make concurrent queue act like serial queue • Other way to make concurrent queue serial?

Slide 24

Slide 24 text

Synchronize Multiple Blocks • dispatch_barrier • dispatch_apply void dispatch_apply( size_t iterations, dispatch_queue_t queue, void (^block)(size_t)); • dispatch_group • Coordinate multiple queues

Slide 25

Slide 25 text

dispatch_io • Use dispatch_io for any I/O operations • Do not “block” in a block execution on a queue

Slide 26

Slide 26 text

NSOperationQueue • Implemented in terms of GCD • Higher level of abstraction (better?) • Fixed width concurrent queues • Implement easily with semaphores • Simulate with N serial queues (danger) • Operation dependencies