1
votes

I believe I understand the behavior of atomic properties (and vs nonatomic ones) but I am somewhat confused by frequent reference to the notion that atomicity "does not guarantee thread safety". This statement, made often in the context of explaining atomic properties confuses me a bit, because to my read, in the obvious sense, thread safety at the property is exactly what you're getting (though no more).

My understanding is that:

  • An atomic property (which is the default, versus an explicit nonatomic) is guaranteed to never read back a garbage value due to multiple writer threads. In other words, if the write of the value itself requires multiple steps (like multiple word writes in memory), that write will be atomic. Thus a read of the property from a given thread will always reflect a value that was written in its entirety at some point in the past, although of course a subsequent read may show some different value.

  • If reading (or indeed writing) a property is part of an operation that requires any further guarantees-- for example, updating two properties that are semantically linked, or needing to act on the current value of a property which must be assumed to be held constant until the act is complete-- then further locking or synchronization on the part of the programmer is required for the semantics overall to be thread safe.

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?
  2. 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.
  3. 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.

Rob Napier's answer here suggests agreement with #2 above. Would appreciate someone well versed in practical usages of atomic to let me know if I've got the right idea here.

2
“Under what broad circumstances is an atomic property actually useful?” It usually isn’t. In fact it usually gets in your way. That’s why Objective C synthesized property accessors are nonatomic by default.matt
@matt That doesn't seem to be the case according to the docs. Property accessors are said to be atomic by default (unless I'm misunderstanding you) which surprises me. developer.apple.com/library/archive/documentation/Cocoa/…Ben Zotto
Oh yeah, you’re right. What I should have said was, that’s why when you declare a property you always say nonatomic. :)matt
See [What's the difference between the atomic and nonatomic attributes? ](stackoverflow.com/questions/588866/…), in particular bbum's answer and the comments on it. You will see remarks on structures and pointers where it is important to get a valid read and some people choose to use atomic to achieve that, while others choose to rely on main thread sequentiality or other sync mechanisms. I'll suggest (flame suit on ;-)) there is no single correct answer to this one and a lot of strongly held views!CRD

2 Answers

1
votes

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.

0
votes

It is not thread safe, that means if thread A is accessing your variable, then thread B, C, D also can access and make changes to it. So at the end of thread A, there is no knowing what the variable holds.