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

Triangle Cocoa

September 27, 2012
Tweet

More Decks by Triangle Cocoa

Other Decks in Programming

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