simply mobile
About Me



Used to be a Linux kernel developer
Currently developing hardware accessories for iOS




                   © 2011
What this talk isn’t about




          © 2011
What this talk isn’t about


Hardware accessories




                  © 2011
What this talk isn’t about


Hardware accessories
App Store overnight success




                  © 2011
What this talk isn’t about


Hardware accessories
App Store overnight success
POSIX threads




                  © 2011
150% thread content




       © 2011
Plan


1. Why we love and hate threads
2. Grand Central Dispatch
3. NSThread class




                     © 2011
Threading




  © 2011
Threading


Not only for multi-core chips




                   © 2011
Threading


Not only for multi-core chips
Responsiveness is the king




                   © 2011
Threading


Not only for multi-core chips
Responsiveness is the king
“The snappy”




                   © 2011
Threading


Not only for multi-core chips
Responsiveness is the king
“The snappy”
Asynchronicity




                   © 2011
Half-measures


Asynchronous I/O
CoreData
Notifications and KVO




                   © 2011
General solution



Threads




               © 2011
Downsides


Overhead
Especially on embedded systems
#1 issue: threads are difficult




                     © 2011
Really?

Thread management
IPC, messaging, synchronization
Locking
Reentrancy
???



                   © 2011
Solution



Grand Central Dispatch




                  © 2011
Grand Central Dispatch


Language features
Runtime libraries
System enhancements




                    © 2011
Together



Automate thread management




                 © 2011
Language features: blocks


Small, self-contained pieces of code
Anonymous, inline collection of code
Available: Snow Leopard, iOS 4.0




                    © 2011
Blocks features


Typed arguments
Return value
Access (and modify) variables




                   © 2011
Mainly useful as



Callbacks
Self-contained units of work




                   © 2011
Syntax


BOOL (^block)(void);
BOOL areKittensCute = YES;
block = ^{ return areKittensCute; };




                    © 2011
Example
- (void)blink:(UIColor *)color

{

    self.view.backgroundColor = color;

    [UIView animateWithDuration:1.0
animations:^{self.view.backgroundColor = [UIColor
darkGrayColor];}];

}




                       © 2011
Grand Central API

GCD provides FIFO queues for blocks
Three types:
   Main
   Concurrent
   Serial



                  © 2011
Concurrent queues


Blocks dequeued in FIFO order
… but run concurrently if resources allow
Finish in any order
Created automatically




                      © 2011
Serial queues


Useful for serialization of tasks
Created manually
dispatch_queue_create(“com.yourname.queue”, NULL);




                     © 2011
Really?

Thread management
IPC, messaging, synchronization
Locking
Reentrancy
???



                   © 2011
When queues are not enough



 Dispatch sources




                    © 2011
Dispatch source API


C-level API
Can monitor for events (signals, data) and dispatch
handlers to appropriate queues
Low-level, useful for OS X but maybe not for iOS




                    © 2011
Back to square one



NSThread class




                 © 2011
The real thing


Cost of threads:
Creation time
Memory footprint (512 kB)
Design overhead




                   © 2011
Conclusion — Don’t use
       threads!




        © 2011
… unless you have no other
          choice



High level event monitoring




                   © 2011
Thread lifecycle

1. Initialize
2. Start
   1. Create autorelease pool, setup sources
   2. Do work
3. Cancel
4. Drain pool


                      © 2011
Thread init



newThread = [[NSThread alloc] initWithTarget:self
selector:@selector(newThreadEntryPoint:) object:nil];




                       © 2011
Entry point


- (void)newThreadEntryPoint:(id)param
{
    …
}




                       © 2011
Thread start



[newThread start];




                     © 2011
Housekeeping


- (void)newThreadEntryPoint:(id)param
{
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]
init];
    …
}




                       © 2011
Get to work


Two options:
  Execute a predefined workset
  Monitor for events
Run loop




                  © 2011
Event sources

NSInputStream *catnipStream;

[catnipStream setDelegate:self];

[catnipStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];

[catnipStream open];




                       © 2011
Running the loop


do {

[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];

       } while (!done);




                          © 2011
The whole package

- (void)runThread


{
    newThread = [[NSThread alloc] initWithTarget:self selector:@selector(newThreadEntryPoint:)
object:nil];
    [newThread start];
}

- (void)newThreadEntryPoint:(id)param
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [catnipStream setDelegate:self];
    [catnipStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [catnipStream open];

    do {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    } while (!done);
}




                                          © 2011
Reuse & recycle



What if I need on-demand threads?




                  © 2011
Run loop maintenance



do {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
    beforeDate:[NSDate distantFuture]];
} while (!done);




                             © 2011
Run loop maintenance



do {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
    beforeDate:[NSDate distantFuture]];
} while ([[NSThread currentThread] isCancelled] == NO);




                             © 2011
Run loop maintenance



do {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
    beforeDate:[NSDate dateWithTimeIntervalSinceNow:5]];
} while ([[NSThread currentThread] isCancelled] == NO);




                             © 2011
Clean up!


[catnipStream close];

[catnipStream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];

[catnipStream setDelegate:nil];




                        © 2011
A lot of code?
     - (void)runThread
{
    newThread = [[NSThread alloc] initWithTarget:self selector:@selector(newThreadEntryPoint:)
object:nil];
    [newThread start];
}

- (void)newThreadEntryPoint:(id)param
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [catnipStream setDelegate:self];
    [catnipStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [catnipStream open];

    do {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate
dateWithTimeIntervalSinceNow:5]];
    } while ([[NSThread currentThread] isCancelled] == NO);

    [catnipStream close];
    [catnipStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [catnipStream setDelegate:nil];
    [pool drain];
}




                                          © 2011
More maintenance

        Consider draining the autorelease pool from within
        the loop if the thread will be running for a long time

        do {


        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate
dateWithTimeIntervalSinceNow:5]];
        [pool drain];
        pool = [[NSAutoreleasePool alloc] init];
    } while ([[NSThread currentThread] isCancelled] == NO);




                                          © 2011
How to quit?



[newThread cancel];
Safe to use from any thread




                   © 2011
Conclusions




iOS applications are heavily threaded internally
Main thread, web rendering thread etc.
GCD is also implemented via threads


                    © 2011
Caveats


Key-value observers are always executed in the
current thread context
What happens when KVO from secondary threads is
used to handle or update UI outlets?




                   © 2011
Solution

performSelectorOnMainThread:(SEL)aSelector
withObject:(id)arg waitUntilDone:(BOOL)wait
(on secondary thread)
[self
performSelectorOnMainThread:@selector(updateField
s:) withObject:data waitUntilDone:YES];



                  © 2011
Why?



Responsiveness!




                  © 2011
Questions?



     Karol Kozimor
karol.kozimor@iosyn.com




     © 2011
More info

Concurrency Programming Guide
  Operation Queues
Threading Programming Guide
WWDC 2011: Blocks and Grand Central Dispatch in
Practice



                 © 2011

Threading in iOS / Cocoa Touch