Tuesday, November 6, 2012

Thread in iOS (Theory)

Thread in iOS

Threads are one of several technologies that make it possible to execute multiple code paths concurrently inside a single application. 
Threads are a relatively lightweight way to implement multiple paths of execution inside of an application.

Inside each program, however, exists one or more threads of execution, which can be used to perform different tasks simultaneously.
The system itself actually manages these threads of execution, scheduling them to run on the available cores and preemptively interrupting them as needed to allow other threads to run.

From a technical standpoint, a thread is a combination of the kernel-level and application-level data structures needed to manage the execution of code.
threads provide a way to increase performance in some types of applications.

  • The term thread is used to refer to a separate path of execution for code.
  • The term process is used to refer to a running executable, which can encompass multiple threads.
  • The term task is used to refer to the abstract concept of work that needs to be performed.

1.Cocoa threads : Cocoa implements threads using the NSThread class. Cocoa also provides methods on NSObject for spawning new threads and executing code on already-running threads.

2.POSIX threads : POSIX threads provide a C-based interface for creating threads. If you are not writing a Cocoa application, this is the best choice for creating threads.

3. Multiprocessing Services : Multiprocessing Services is a legacy C-based interface used by applications transitioning from older versions of Mac OS. Instead, you should use the NSThread class or POSIX threads.

Threads are relatively expensive to create in terms of memory and time.
Thread States : After starting a thread, the thread runs in one of three main states: running, ready, or blocked.
If a thread is not currently running, it is either blocked and waiting for input or it is ready to run but not scheduled to do so yet.
Thread entry-point : When you create a new thread, you must specify an entry-point function/method for that thread.

Run Loop  : 
A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread busy when there is work to do and put your thread to sleep when there is none.
A run loop puts its thread to sleep when there is nothing to do, it eliminates the need for polling, which wastes CPU cycles and prevents the processor itself from sleeping and saving power.
To configure a run loop, all you have to do is launch your thread, get a reference to the run loop object, install your event handlers, and tell the run loop to run.
If you plan to create long-lived secondary threads, however, you must configure the run loop for those threads yourself.
Thread Synchronization
Locks (NSLock class)
Locks provide a brute force form of protection for code that can be executed by only one thread at a time. The most common type of lock is mutual exclusion lock, also known as a mutex. When a thread tries to acquire a mutex that is currently held by another thread, it blocks until the lock is released by the other thread. 
You can use locks to protect a critical section of your code, which is a segment of code that only one thread at a time is allowed access.

Conditions (NSCondition Class)
A condition acts as a gatekeeper, blocking a given thread until the condition it represents becomes true. When that happens, the condition releases the thread and allows it to continue.

Atomic operations
Atomic operations are another way to protect and synchronize access to data. Atomic operations offer a lightweight alternative to locks in situations where you can perform mathematical or logical operations on scalar data types. Atomic operations use special hardware instructions to ensure that modifications to a variable are completed before other threads have a chance to access it.

Inter-thread Communication
At some point, communication between threads becomes necessary. 
Creating a multithreaded application is hard. Even if you are very careful and lock shared data structures at all the right junctures in your code, your code may still be semantically unsafe.
A thread’s job is to do work for your application, but if the results of that job are never used, what good is it? so you need a way to get information from one thread to another.
There are many ways to communicate between threads.
1.Direct messaging
This capability means that one thread can essentially execute a method on any other thread.

2.Global variables, shared memory, and objects

Another simple way to communicate information between two threads is to use a global variable, shared object, or shared block of memory.

Shared variables must be carefully protected with locks or other synchronization mechanisms to ensure the correctness of your code. Failure to do so could lead to race conditions, corrupted data, or crashes.

3.Conditions (NSCondition Class)

Conditions are a synchronization tool that you can use to control when a thread executes a particular portion of code. 

A thread waiting on a condition remains blocked until that condition is signaled explicitly by another thread.
4. Run loop
Run loop sources put your thread to sleep automatically when there is nothing to do, which improves your thread’s efficiency.

5.Ports and sockets
Ports and sockets can be used to communicate with external entities, such as other processes and services. so your thread sleeps when there is no data waiting on the port.

6.Message queues
7.Cocoa distributed objects

Thread Management :

Every application starts with a single thread, which runs the application's main function. Applications can spawn additional threads, each of which executes the code of a specific function.
When an application spawns a new thread, that thread becomes an independent entity inside of the application's process space. Each thread has its own execution stack and is scheduled for runtime separately by the kernel. A thread can communicate with other threads and other processes, perform I/O operations, and do anything else you might need it to do. Because they are inside the same process space, however, all threads in a single application share the same virtual memory space and have the same access rights as the process itself.

Thread Costs:
Threading has a real cost to your program (and the system) in terms of memory use and performance. Each thread requires the allocation of memory in both the kernel memory space and your program’s memory space. 
1. Kernel data structures [ 1 kb] : This memory is used to store the thread data structures and attributes, much of which is allocated as wired memory and therefore cannot be paged to disk.

2. Stack space [512 KB (secondary threads) 8 MB (OS X main thread) 1 MB (iOS main thread) ] :  The minimum allowed stack size for secondary threads is 16 KB and the stack size must be a multiple of 4 KB.

3. Creation time [90 microseconds] : This value reflects the time between the initial call to create the thread and the time at which the thread’s entry point routine began executing.

Creating a Thread :

There are two ways to create a thread
Use the detachNewThreadSelector:toTarget:withObject: class method to spawn the new thread. (is supported in all versions of OS X)
Create a new NSThread object and call its start method. (Supported only in iOS and OS X v10.5 and later.)

* Both techniques create a detached thread in your application. A detached thread means that the thread’s resources are automatically reclaimed by the system when the thread exits.

1. Create Thread using "detachNewThreadSelector:toTarget:withObject " method
To detach a new thread, you simply provide the name of the method (specified as a selector) that you want to use as the thread’s entry point, the object that defines that method, and any data you want to pass to the thread at startup.

Example :
[NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil];

2. Create Thread using " initWithTarget:selector:object " method

This method takes the exact same information as the detachNewThreadSelector:toTarget:withObject: method and uses it to initialize a new NSThread instance. It does not start the thread, however. To start the thread, you call the thread object’s start method explicitly.
Example :

NSThread* myThread = [[NSThread alloc] initWithTarget:self

[myThread start];  // Actually create the thread
[myThread cancel];
[NSThread exit];

3. Create Background thread with NSObject class

The performSelectorInBackground:withObject: method creates a new detached thread and uses the specified method as the entry point for the new thread.if you have some object ( myObj) and that object has a method called doSomething that you want to run in a background thread.


[myObj performSelectorInBackground:@selector(doSomething) withObject:nil];

* this method is the same as if you called the detachNewThreadSelector:toTarget:withObject: method of NSThread with the current object.

Autorelease Pool

Note : you would need to set up an autorelease pool (if you were not using garbage collection) and configure the thread’s run loop if you planned to use it. The autorelease pool catches any objects that are autoreleased from that thread.
Because the top-level autorelease pool does not release its objects until the thread exits, long-lived threads should create additional autorelease pools to free objects more frequently.

- (void)doSomething {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
*** code that should be run in the new thread goes here ***
[pool release];

Thread Attributes

1. change thread stack size

Allocate and initialize an NSThread object (do not use the detachNewThreadSelector:toTarget:withObject: method). Before calling the start method of the thread object, use the setStackSize: method to specify the new stack size.

Thread Types:

1.Detached threads

Most high-level thread technologies create detached threads by default. In most cases, detached threads are preferred because they allow the system to free up the thread’s data structures immediately upon completion of the thread. Detached threads also do not require explicit interactions with your program.

2.Joinable threads

You can think of joinable threads as akin (similar) to child threads.Although they still run as independent threads, a joinable thread must be joined by another thread before its resources can be reclaimed by the system.

* At application exit time, detached threads can be terminated immediately but joinable threads cannot. Each joinable thread must be joined before the process is allowed to exit. Joinable threads may therefore be preferable in cases where the thread is doing critical work that should not be interrupted, such as saving data to disk.

Thread Priority:

you can use the setThreadPriority: class method of NSThread to set the priority of the currently running thread.

It is generally a good idea to leave the priorities of your threads at their default values. Increasing the priorities of some threads also increases the likelihood of starvation among lower-priority threads.

Terminating a Thread:

The recommended way to exit a thread is to let it exit its entry point routine normally. Killing a thread prevents that thread from cleaning up after itself. 

Using the @synchronized Directive

The @synchronized directive is a convenient way to create mutex locks on the fly in Objective-C code.


- (void)myMethod:(id)anObj
        // Everything between the braces is protected by the @synchronized directive.


Grand Central dispatch (Asynchronous Task) / NSOperations

Important: GCD is a C level API; it does not catch exceptions generated by higher level languages. Your application must catch all exceptions before returning from a block submitted to a dispatch queue.