systems: Processes: each unit has its own virtual memory Threads: sub-units in process that shared virtual memory Source : Modern Operating Systems - Andrew S. Tannenbaum 4 / 36
to units by the scheduler : The unit runs, sleeps, wakes up, sleeps, ..., stops The strategy used depends on the operating system. Multi-tasks systems often use a variant of Round- Robin with priorities. It is a time based multiplexer algorithm. Source : Modern Operating Systems - Andrew S. Tannenbaum 5 / 36
processors have several cores : Threads are really parallelized Using thread in encouraged Using too many threads could leads to threading overhead Source : The overhead of spawning threads (a performance experiment) - Matt Gallagher 7 / 36
used for process/thread communication : Semaphore/Mutex Spinlock Message passing Bad using of thoses tools could lead to : Race conditions Deadlock 8 / 36
is a single threaded loop that dispatch events synchronously to theirs handlers. This thread is generally called the main thread On BSD/Darwin, it is based on kqueue, on others systems, it relies on select, poll or eppoll system calls Idea : # -> No busy wait due to system calls or kqueue while there are still events to process: e = get the next event if there is a callback/handler associated with e: call the callback/handler For more informations : http://en.wikipedia.org/wiki/Reactor_pattern An introduction to libuv 10 / 36
Handlers for events are created using the CFRunLoopSourceRef object. For input events as mouse or keayboard events, NSPort, NSConnection and NSTimer, the corresponding CFRunLoopSourceRef are managed automatically. It's possible to create custom sources of events : Threading Programming Guide - Configuring Run Loop Sources 12 / 36
of independently executing processes. Parallelism : Programming as the simultaneous execution of (possibly related) computations. A talk on the subject by Rob Pike (golang team) : Concurrency vs Parallelism 14 / 36
are usually the same : Downloading data asynchronously and notify the GUI Compute heavy data in background and notify the GUI Synchronize several concurrent tasks at some point of execution Ensure thread-safety of API Example of patterns to use : Producer/Consumer Working Queue Message passing 15 / 36
tools to implement them : NSThread, [NSThread detachNewThreadSelector:toTarget:withObject:] [NSObject performSelectorInBackground:withObject:], [NSObject performSelectorOnMainThread:withObject:] NSLock NSRecursiveLock NSConditionLock NSDistributedLock NSCondition @synchronize(lock) statement Atomic operations OSAtomicOr32, OSAtomicAdd32,... POSIX threads, conditions and mutex Drawbacks : You may feel to reinvent the wheel Boilerplate code Synchronisation with the main thread ? Code not always easy to read/understand Easy to enter in race conditions Efficiency vs speed in coding ? 16 / 36
*/ id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA]; while(true) { [condLock lock]; /* Add data to the queue. */ [condLock unlockWithCondition:HAS_DATA]; } /* Consumer */ while (true) { [condLock lockWhenCondition:HAS_DATA]; /* Remove data from the queue. */ [condLock unlockWithCondition:(isEmpty ? NO_DATA : HAS_DATA)]; // Process the data locally. } 17 / 36
The thread pool pattern is an abstraction over threads that helps to target on the essential : Number of thread managed by the framework Number of thread otpimized for the system Banning thread from the semantic Examples : QThreadPool in Qt framework Parallel Extensions in .NET GCD and NSOperation on Darwin 20 / 36
and released in the libdispatch library. libdispatch is open source C API Block oriented (Objective-C2.0) Queues represented by a unique structure : dispatch_queue_t Tasks are represented by blocks Premption capability with priorities Optimized synchronisation tools (I/O, Buffer, General) Terse code 22 / 36
serial Serial queue : tasks are executed one a time in FIFO style. Concurrent queue : tasks are runned concurrently For each application, the OS provide default queues : One main queue : queue associated with the main thread Four concurrent queues with descending priorities 23 / 36
with dispatch_block_t: typedef void (^dispatch_block_t)(void); dispatch_block_t block_task = ^{ printf("Task1 \n");} Representing tasks with functions with dispatch_function_t: typedef void (*dispatch_function_t)(void*) void function_task(void * context){ printf("Task with function \n"); } Enqueueing task is either synchronously or asynchronously: //Return immediatly dispatch_async(myQueue,block_task); dispatch_async_f(myQueue,function_task); //Wait for task to end dispatch_sync(myQueue,block_task); dispatch_sync_f(myQueue,function_task); You're encouraged to use blocks and asynchronous enqueueing as often as possible. 25 / 36
dispatch_apply,dispatch_apply_f : execute task multiple times dispatch_after,dispatch_after_f: execute a task after a specified amount of time dispatch_once : execute the task only once during the application life-cycle 26 / 36
in a set to synchronize. It is based on a counter of outstanding tasks dispatch_group_t group = dispatch_group_create(); dispatch_block_t task1 = ^{ printf("Task 1\n");}, task2 = ^{ printf("Task 2\n");}, task3 = ^{ NSInteger i; for(i = 0; i < INT16_MAX; ++i); }; dispatch_queue_t queue; queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0); dispatch_group_async(group,queue,task1); dispatch_group_async(group,queue,task2); dispatch_group_async(group,queue,task3); /* Wait for the oustanding tasks counter to be null*/ dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 27 / 36
increment/decrement the outstanding tasks counter with dispatch_group_enter and dispatch_group_leave dispatch_group_enter(group); dispatch_group_async(group,queue,^{ awesome_function_with_callback(^{ /* ... */ dispatch_group_leave(group); }) }); dispatch_group_wait(group, DISPATCH_TIME_FOREVER); Schedule a block when all previous committed blocks end with dispatch_group_notify dispatch_group_notify(group, queue, ^{ printf("I am called at the end !\n");} ); 28 / 36
Lot of others features : Target Queue Semaphores Dispatch sources Queue Data Dispatch I/O See : Concurrency Programming Guide NSBlog - Topics on GCD CocoaSamurai - Guide to blocks and grand central dispatch WWDC 2011 - Mastering Grand Central Dispatch WWDC 2010 - Introducing Blocks and Grand Central Dispatch on iPhone WWDC 2010 - Simplifying iPhone App Development with Grand Central Dispatch 30 / 36
built on top of GCD : Higher-level of abstraction Objective-C API Ready to use with Apple Framework : UIKit, AVFoundation, MapKit, OpenGL, ... Small API - Enough for most basic cases All magic is hidden in two objects : NSOperation : represents tasks NSOperationQueue : represents queue 32 / 36
Abtract class representing a task. Need to subclass -> See documentation Manage queue and thread priorities Completion block feature Summerize : 1. Implement start , main , isConcurrent , isFinished and isExecuting methods 2. Test for cancel events in your main and start methods when necessary 3. Add operation to a queue 34 / 36