Atomic Properties VS Thread-Safe in Objective-C

Atomic properties vs thread-safe in Objective-C

An atomic property in Objective C guarantees that you will never see partial writes.
When a @property has the attribute atomic it is impossible to only partially write the value. The setter is like that:

- (void)setProp:(NSString *)newValue {
[_prop lock];
_prop = newValue;
[_prop unlock];
}

So if two threads want to write the value @"test" and @"otherTest" at the same time, then
at any given time the property can only be the initial value of the property or @"test" or @"otherTest".
nonatomic is faster but the value is a garbage value and no partial String of @"test"/@"otherTest" (thx @Gavin) or any other garbage value.

But atomic is only thread-safe with simple use.
It is not garantueed.
Appledoc says the following:

Consider an XYZPerson object in which both a person’s first and last
names are changed using atomic accessors from one thread. If another
thread accesses both names at the same time, the atomic getter methods
will return complete strings (without crashing), but there’s no
guarantee that those values will be the right names relative to each
other. If the first name is accessed before the change, but the last
name is accessed after the change, you’ll end up with an inconsistent,
mismatched pair of names.

I never had a problem using atomic at all. I designed the code that way, that there is not problem with atomic properties.

atomic properties vs thread safety

In other words, the writing and reading of the atomic property itself is, in fact, “thread safe” (protected from corruption by multiple writers) but of course that protection doesn't extend to any broader logic.

  1. Is this an accurate understanding?

Largely yes.

I would shy away from using the term “thread safe” in that context, though, especially in the context of objects, because the notion that a pointer is not corrupted is a far cry from any practical sense of thread safety of the object itself, much less the broader application logic.


  1. Under what broad circumstances is an atomic property actually useful? I could contrive some simple examples where a property is some sort of counter or changing object that doesn't need to reflect current state, etc, but those seem uncommon versus multithreading scenarios where you really do need explicit locking around the access-- in which case you could have just used nonatomic on the actual property all along.

They can be useful when dealing with primitive data types in specific scenarios (e.g., a boolean state property designating whether some background process is done). They also can be useful in special cases where you are dealing with immutable, stateless objects.

But in most multithreaded scenarios, atomic properties generally fail to achieve thread safety.


  1. Why exactly do people consistently say that atomicity doesn't “guarantee thread safety”? That seems only true in the same way that an NSLock doesn’t guarantee thread safety or synchronized doesn't guarantee thread safety-- a warning for the uninitiated? Otherwise it seems a confusing designation since the very point of these synchronization mechanisms is that they are for use in thread safe design and they are known to be reliable in their designed operation.

We do this because there were people (e.g. https://stackoverflow.com/a/17571453/1271826) who incorrectly suggest that atomic properties achieve thread-safety when it almost always fails to do so. Back in the day, it seemed like whenever someone asked a question about thread safety, someone would chime in with “oh, use atomic properties”. There seemed to be a perennial conflation of “thread safety” and the modest protection against corruption that atomic offers.

So, yes, “has nothing to do with thread safety” is a bit strong. But in the vast majority of cases, atomic properties fail to achieve thread safety, and in the presence of properly implemented synchronization (such as locks, @synchronized, GCD, etc.), just introduce unnecessary overhead.

This is very different than the other synchronization mechanisms (such as locks, etc.). With proper implementation of these mechanisms, one invariably can achieve thread safety. But in many cases (most cases?) atomic simply won’t do the job. Sure, atomic can mitigate one very narrow type of corruption of values/pointers, but that generally doesn’t make one’s code thread safe.

Which is threadsafe atomic or non atomic?

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.

Which is thread Safe atomic or non-atomic?

As is mentioned in several answers to the posted question, atomic is thread safe. This means that getter/setter working on any thread should finish first, before any other thread can perform getter/setter.

In Objective-C (and Swift) are weak properties thread safe?

weak is part of ARC, and is promised to be atomic by Clang in the way you're describing. See particularly section 4.2 Semantics in the Automatic Reference Counting documentation for Clang.

Of specific interest for this are these sections (emphasis added):

Reading

For __weak objects, the current pointee is retained and then released at the end of the current full-expression. This must execute atomically with respect to assignments and to the final release of the pointee.

Assignment

For __weak objects, the lvalue is updated to point to the new pointee, unless the new pointee is an object currently undergoing deallocation, in which case the lvalue is updated to a null pointer. This must execute atomically with respect to other assignments to the object, to reads from the object, and to the final release of the new pointee.

Note that many other operations are not atomic, in particular strong assignments (for example, assigning a strong property on two different threads). But the retain counting itself is thread safe, which is really the piece you're worried about here. You are free to retain and release objects on any thread, and the retain count at the end will be correct, including "implicit" releases due to weak assignment. It's all the direct result of the following:

  • objc_retain is defined to be "exactly as if the object had been sent the retain message."
  • "Object allocation and retain count functions" are explicitly thread-safe.

The upshot of all of this is that, unlike most parts of Cocoa, reference counting is almost always going to be safely handled across threads.

Is atomic property thread safe in ObjC++

First of all: No, it is not said that "atomicity" is thread-safety neither in general nor for declared properties, neither in Objective-C nor in C++. Atomicity means that no getter or setter (it is on object level, so even accessors of other properties) run simultaneously. But it says nothing of what happens immediately after setting or getting a value. To have thread-safety you have to do more. (Therefore atomicity of declared properties are akin of meaningless.) In the past atomic/nonatomic had more to do with memory management. This became less important by far since we have ARC.

After this, it is probably less important to answer to your Q: It is not documented, but has been documented a bit more in past. Apple said that they used an object level lock. Since even very simple NSLock uses pthreads internally – that's documented –, I assume that they work, if you created the threads with pthread.


A little sample:

@interface Person
@property NSString *fristName;
@property NSString *lastName;
@end

@implementation Person
@end

Control flow 1:

person.firstName = @"Chris";
person.lastName = @"Kienle";

Control flow 2:

person.firstName = @"Amin";
person.lastName = @"Negm";

NSString *combined = [NSString @"%@ %@", person.firstName, person.lastName];

Possible result with perfect atomic and thread-safe accessors:

Christian Negm


Related Topics



Leave a reply



Submit