Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Grand Central Dispatch by Jody Hagins

Grand Central Dispatch by Jody Hagins

Jody discussing using GCD in iOS and Mac applications from CocoaHeads September in Durham

F13b7ea691e49d2cb953e10317f21976?s=128

Triangle Cocoa

September 27, 2012
Tweet

Transcript

  1. Gentle Introduction to Grand Central Dispatch Better to Remain Silent

    and Be Thought a Fool than to Speak and Remove All Doubt
  2. 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
  3. Queues • Just a data structure (FIFO) • List of

    Blocks • enqueue • Atomic, lock-free • dequeue • Automatically handled by the “system”
  4. Serial Queue enqueue dequeue

  5. Concurrent Queue enqueue dequeue

  6. 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
  7. 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);
  8. 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
  9. 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
  10. 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
  11. dispatch_async • Handle all up to iOS6 / Mountain Lion

    #include <dispatch/dispatch.h> #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
  12. 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
  13. 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); }); }
  14. 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. }); });
  15. 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 }); });
  16. 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
  17. 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
  18. Suspend / Resume • All dispatch objects (including queues) can

    be suspended and resumed • Immediately after running block(s)
  19. 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);
  20. 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?
  21. 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
  22. 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
  23. 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?
  24. 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
  25. dispatch_io • Use dispatch_io for any I/O operations • Do

    not “block” in a block execution on a queue
  26. 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