Tag Archives: threads

Thread Safety in ios

ref – http://quellish.tumblr.com/post/101831085987/implementing-thread-safety-in-cocoa-ios

You have just introduced “threads” to your application, because doing everything on the same thread as the UI was starting to noticeably bog things down. At some point you have run into strange crashes or exceptions. Your application no longer behaves as it used to.

One problem you have likely introduced is sharing data between threads. If two threads can be changing something, you’re asking for trouble. The common solution to this problem is to protect access to that resource: to introduce some form of locking on the resource to only allow one thing to touch it at a time.

In Objective-C there are a number of ways to deal with this, with the most common being use of the @synchronized keyword to protect access to a block of code.
The @synchronized keyword

In Objective-C the @synchronized keyword provides an implicit reentrant lock on a unique identifier for a block of code. For example:

This prevents the code inside that statement from executing until any contention on foo is released. This prevents more than one thread from using that lock at a time.

Because the lock is implicit, there is overhead even when the lock is not in contention. If nothing else is accessing the lock, the system still has to find the lock, which takes time. The lock used is recursive, which is more expensive than a non-recursive lock. Additionally, the @syncrhonized keyword does put into place an exception handler that adds some additional overhead. Because @synchronized uses a lock, it’s possible to use it in ways that result in a deadlock.

@synchronized is a blunt instrument, and unfortunately is often used to hammer away “threading problems”.

Lock-free synchronization

The point of synchronizing access to something is to ensure only one thing can access it at a time. On MacOS and iOS we have the concept of queues for concurrency. A serial queue is an ideal way to protect access without the potential costs of locking. If every access to the protected resource occurs through a serial queue the problem is solved – the queue guarantees that only one thing will be accessing it at a time. For example:

Because the serial queue executes work in FIFO order and only one block at a time, the statement is protected. Unlike using a lock, this can’t deadlock.

This is the preferred method for protecting a resource shared between threads on MacOS and iOS.
Not needing synchronization at all

The recommended solution for this problem is not to have it all. If you are sharing a mutable resource between threads, question why.

You may have noticed that much of Foundation is class clusters that provide both immutable (i.e. NSString) and immutable (i.e. NSMutableString) versions of a given class cluster object. An immutable object cannot be changed after it is created – it has a finite, determinate state and life cycle. Because of this, immutable objects are safe to exchange betweeen threads – there is no problem with two threads changing the object at the same time. Mutable objects should be considered unsafe unless they are specifically documented to be safe to access across threads.

Unfortunately few objective-c developers follow this practice even though it is one of the SOLID object oriented design principles. The developer will run into a mysterious crash or exception, google it, and after reading a few Stack Overflow articles start stamping @synchronized all over the place.
In practice

Implementing a reader-writer lock or the equivalent in objective-c is easy, and easy to get wrong. You will commonly see something like this:

Which isn’t effective for several reasons. Each method is synchronizing on self, so ANY access to self or it’s members will cause a contention.

By overriding the accessor methods for the foo property and accessing the instance variables directly the application may not be correctly managing the memory associated with foo.

A better implementation would be:

This uses a private property to ensure correct memory management. Note that because it’s of type id, we retain it strongly. If foo were a type that is a class cluster, we would prefer declaring it as copy rather than strong. That would ensure that even if it were set with a mutable object, the accessor would make an immutable copy before setting it. Instead of using @synchronized to provide an implicit lock, we’re using a serial queue to protect access to the private property. Note that in the case where we return the value in the getter we use dispatch_sync to make the calling thread wait for the result. This does use a lock, but the lock does not have most of the disadvantages of @synchronized and is only used in the reading case. An alternative would be to pass a block to be executed when the value is available:

This not only removes the need to block, but executes asynchronously.

Thread Basics (Instantiations)

SomeClass header

SomeClass implementation

main

log output:

Thread B processing on object 0x7fe839416a70 ‘s method, member variable address: 0x7fe839416a78, number just changed to 0
Thread B processing on object 0x7fe839416a70 ‘s method, member variable address: 0x7fe839416a78, number just changed to 1
Thread A processing on object 0x7fe83960e340 ‘s method, member variable address: 0x7fe83960e348, number just changed to 0
Thread A processing on object 0x7fe83960e340 ‘s method, member variable address: 0x7fe83960e348, number just changed to 1
Thread B processing on object 0x7fe839416a70 ‘s method, member variable address: 0x7fe839416a78, number just changed to 2
Thread B processing on object 0x7fe839416a70 ‘s method, member variable address: 0x7fe839416a78, number just changed to 3
Thread A processing on object 0x7fe83960e340 ‘s method, member variable address: 0x7fe83960e348, number just changed to 2

As you can see

Thread A processes on object 0x7fe83960e340
Thread B processes on object 0x7fe839416a70

The access different member variables, in particular

Thread A processes on object 0x7fe83960e340’s member variable 0x7fe83960e348
Thread B processes on object 0x7fe839416a70’s member variable 0x7fe839416a78

Both threads do their work on their own respective objects because those objects were allocated on the thread’s own stack in main’s

Threads Basics (static, class methods, and singletons)

Class methods are shared by threads

All methods who run a class method on a class name are using the same class and running through that one method. That class method acts as an entry point. You do this by looking at the address of self.

If you run couple of threads through this classMethod, you should something like this:

classMethod – thread B, self address is: 0x107159380
classMethod – thread A, self address is: 0x107159380
classMethod – thread C, self address is: 0x107159380

They all have the same address for ‘self’. Which means there exist only one blueprint of the class in which these class methods belong to.

static variables are shared by threads

you’ll see that in the output, they all display the static variable’s address, which is the same for all threads:

classMethod – thread B, local static int number’s address is: 0x1071594e8
classMethod – thread C, local static int number’s address is: 0x1071594e8
classMethod – thread A, local static int number’s address is: 0x1071594e8

local variables are not shared. They belong to their own thread stack

you’ll see from output the the addresses of the local variable is different, which tells us that each thread have their own local variables:

classMethod – thread D, local int number’s address is: 0x11420fc44
classMethod – thread B, local int number’s address is: 0x114109c44
classMethod – thread C, local int number’s address is: 0x11418cc44
classMethod – thread F, local int number’s address is: 0x114315c44
classMethod – thread E, local int number’s address is: 0x114292c44

non-static variables are not allowed

If we were to declare an int number in our class:

and you try to use it in your static method, you’d get an error. Because only static variables are used in static methods. Its not intuitive or possible for a class method to keep track of instantiated variables. It simply does not work this way.

the variable ‘number’ is connected to an instantiation (object) of SomeClass.

No static class variables

You cannot declare ‘number’ in our previous example to be static because in objective c, there are no class static variables.

However, you CAN declare a static variable globally and use it in SomeClass’s static method. That is the basis of how a lot of singletons are made.

Example Singleton

.h

.m

As you notice we don’t let others copy or allocate our singleton by returning self. ….because there can be only 1 singleton.

Full Example

SomeClass header

SomeClass implementation

main – appdelegate

Result

classMethod2 – thread D, self address is: 0x107159380
classMethod – thread B, self address is: 0x107159380
classMethod – thread A, self address is: 0x107159380
classMethod – thread C, self address is: 0x107159380
classMethod2 – thread E, self address is: 0x107159380
classMethod2 – thread F, self address is: 0x107159380
classMethod2 – thread D, local static int number’s address is: 0x1071594ec
classMethod – thread B, local static int number’s address is: 0x1071594e8
classMethod – thread C, local static int number’s address is: 0x1071594e8
classMethod – thread A, local static int number’s address is: 0x1071594e8
classMethod2 – thread F, local static int number’s address is: 0x1071594ec
classMethod2 – thread E, local static int number’s address is: 0x1071594ec
classMethod – thread A, local int number’s address is: 0x114086c44
classMethod2 – thread D, local int number’s address is: 0x11420fc44
classMethod – thread B, local int number’s address is: 0x114109c44
classMethod – thread C, local int number’s address is: 0x11418cc44
classMethod2 – thread F, local int number’s address is: 0x114315c44
classMethod2 – thread E, local int number’s address is: 0x114292c44