31
votes

I searched and found immutable are thread safe while mutable is not. This is fine. But i got misleading notes, blogs, answers about atomic vs non-atomic about thread safety, kindly give an explanation for the answer.

Suppose there is an atomic string property called "name", and if you call [self setName:@"A"] from thread A, call [self setName:@"B"] from thread B, and call [self name] from thread C, then all operation on different thread will be performed serially which means if one thread is executing setter or getter, then other threads will wait. This makes property "name" read/write safe but if another thread D calls [name release] simultaneously then this operation might produce a crash because there is no setter/getter call involved here. Which means an object is read/write safe (ATOMIC) but not thread safe as another threads can simultaneously send any type of messages to the object.

If the property "name" was nonatomic, then all threads in above example - A, B, C and D will execute simultaneously producing any unpredictable result. In case of atomic, Either one of A, B or C will execute first but D can still execute in parallel.

Yours comment on this will help us....

And my question is, "which is thread safe in cocoa, atomic or non-atomic?"

7

7 Answers

68
votes

For ObjC Properties -- Neither are thread safe.

Atomic is more resistant to threading errors. Overall, it is a curious default. The scenarios you would favor atomic for are very few. Atomic can increase the probability of correctness, but it's at too low a level be considered a substitute for a proper locking mechanism. Therefore, if you need thread safety, you still need some other synchronization primitive on top of the atomic reads/writes. If you don't need thread safety (e.g. the instance is immutable or intended to be run from the main thread only), atomic will add nothing.

Being resistant to threading errors is not a 'quality' -- it serves to mask real threading errors and make them more difficult to reproduce and detect.

Also note that mutable vs. immutable types do not actually guarantee threadsafety. 'Mutable' may be used in ObjC names to refer only to the interface -- the internals of an immutable instance may actually have internal mutable state. In short, you cannot assume that a type which has a mutable subclass is thread safe.


Question Expanded:

Suppose there is an atomic string property called "name", and if you call [self setName:@"A"] from thread A, call [self setName:@"B"] from thread B, and call [self name] from thread C, then all operation on different thread will be performed serially which means if one thread is executing setter or getter, then other threads will wait.

If all threads tried to read and/or write to the property at the same time, only one thread would have access at a time and the others would be blocked if the property were atomic. If the property were nonatomic, then they would all have unguarded read and write access to the variable at the same "time".

if another thread D calls [name release] simultaneously then this operation might produce a crash because there is no setter/getter call involved here.

Correct.

Which means an object is read/write safe (ATOMIC) but not thread safe as another threads can simultaneously send any type of messages to the object.

Well, there's really a lot more to it. The common example is:

    @interface MONPerson : NSObject

    @property (copy) NSString * firstName;
    @property (copy) NSString * lastName;

    - (NSString *)fullName;

    @end

Atomic, or nonatomic, you will need a synchronization mechanism (e.g. lock) if one thread is reading from that instance and another is writing to it. You may end up with one MONPerson's firstName and another's lastName -- The object may have changed before the getter's return value is even returned to you, or this can happen:

Thread A:

p.firstName = @"Rob";

Thread B:

p.firstName = @"Robert";

Thread A:

label.string = p.firstName; // << uh, oh -- will be Robert

If the property "name" was nonatomic, then all threads in above example - A,B, C and D will execute simultaneously producing any unpredictable result.

Right - initial symptoms can be reference count imbalances (leak, over-release).

In case of atomic, Either one of A, B or C will execute first but D can still execute in parallel. Kindly comment on this....

Correct. But if you look at the example above -- atomic alone is rarely a suitable replacement for a lock. It would have to look like this instead:

Thread A:

[p lock]; // << wait for it… … … …
// Thread B now cannot access p
p.firstName = @"Rob";
NSString fullName = p.fullName;
[p unlock];
// Thread B can now access p
label.string = fullName;

Thread B:

[p lock]; // << wait for it… … … …
// Thread A now cannot access p
…
[p unlock];

Atomic accessors can average over twenty times slower than nonatomic accesses. As well, if your class needs to be threadsafe and has mutable state, you will likely end up using a lock when it operates in a concurrent scenario. Proper locking provides the all guarantees you need -- atomic accessors are redundant in that scenario, using atomics would only add CPU time. Another good thing about the regular lock is that you have all the granularity you need -- although it is often heavier than the spin lock used for atomics, you will typically need fewer acquires so it ends up being very fast if you use regular locks correctly.

13
votes

atomic guarantees atomic access to the variable but it DOESN'T make your code thread safe. Neither does non-atomic.

With "atomic", the synthesized setter/getter methods will ensure that a whole value is always returned from the getter or set by the setter, regardless of setter activity on any other thread. So if thread A is in the middle of the getter while thread B calls the setter, an actual viable value will be returned to the caller in A. For nonatomic, you have no such guarantees.

9
votes

atomic makes doing the following thread safe.

self.myProperty = value;

or

id value = self.myProperty

it does not make the following thread safe

[myPorperty addObject:value];

Atomic makes it thread safe to set or get a property, but it doesn't make calling any methods of that property itself thread safe.

setting or getting values can take more than one CPU instruction and so that means the setting or getting can be interrupted half way though and another thread can do something making the progress of the previous thread in setting or getting the value invalid.

atomic says set or get the value in a way so that it happens as if it happened in one indivisible instruction and so no other thread can step in half way and screw things up.

Immutable object are thread safe simple because you cannot change them, of cause you can change a property from one immutable object another so that part will not be thead safe unless you make it atomic.

2
votes

There's another property of "atomic" that wasn't mentioned which was needed for thread safety before ARC (and probably still is). First explaining why it's needed: Let's say without ARC, you read an object property and immediately retain it. But another thread could come in just between you reading the property and the retain call, set the object property to nil, causing the object to be deallocated. You send retain to a deallocated object, which is unhealthy. And it would be a very rare bug because it only happens when the timing is just right. To prevent this, atomic object properties always return autoreleased objects.

0
votes
  1. Atomic is thread-safe.
  2. lock as Mutex, spin, or condition which is another type of semaphore. Read more ... https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html
-7
votes

Non atomic is thread safe. Guranted get value of variable.