Cosmos and Atomicity
@interface TheUniverse : Multiverse @property (atomic) Classic * atom; @property (nonatomic) Modern * atom;
(Just squirrel that away for a moment)
I'd wager that most folks are familiar with the classic concept of the atom, namely that an atom consists of three distinct sub-particles: the electron, proton and neutron. And if you're intrepid enough to browse pop-science sites or watch Cosmos as I do, then you know that those fundamental building blocks of the atom can be even further subdivided. (see "Standard Model").
Though long before the equipment existed to be able to test the existance of an atom, people were thinking about what composed everything around them. For example, Greek philosophers postulated that dividing something in half would eventually result in some element that could not be further divided. This basic building block, this concept of an indivisible element, was given the name "atom."
Early on in my time at Flatiron, the question came up of
nonatomic. And the take away from that conversation was to use
nonatomic with reckless abandon. Fair enough -- skipping that lesson all together was a blessing considering at that point we hadn't even studied blocks yet.
Though after an evening of watching Cosmos episodes during the course, I serendipitously made the connection between the concept of the "atom" and "atomic." Could the two be intertwined in some way?
Atomic v. Nonatomic
@property (atomic) Classic * atom;
An atom is an indivisible unit: it exists as a whole, only. An atomic property is an indivisible unit as well: it exists as a wholely encapsulated unit, only.
When we talk atomicity we're actually giving a slight, referential nod to the setter and getter methods that are synthesized by the ObjC compiler at runtime. These methods are responsible for allowing us to reference instance variables rather than directly accessing their values.
These methods are also handled differently depending on their atomicity. An atomic property is guaranteed to be "whole", which means it will never be retrived by its getter while its setter is being called. And why is this important? Although unlikely, it's possible that the
atom property is 1/2 way through having it's value assigned by its setter in Thread A, when suddenly Thread B interjects and requests the value of
atom at that very moment. Well, if the value is updating as it's being requested... what is going to be returned to Thread B? That's what Apple refers to as unexpected behavior.
But theoretically, this atomic property will be sent to Thread B as a whole value. So, it will either be returned as it's value before Thread A executed, or after. But never some partial representation of the two. So if the property
atom is a three-element
NSArray consisting of
@"Electron", @"Proton", @"Neutron" which Thread A changes to
@"Up", @"Strange", @"Top", thread B will receive the array in its state before or after Thread A makes the change -- but not some inbetween state.
In this case it will be received in Thread B as
@[@"Electron", @"Proton", @"Neutron"] or
@[@"Up", @"Strange", @"Top"]... but not some combination of the two, like
@property (nonatomic) Modern * atom;
Lexically, something that is non-atomic means that it can be split apart into discrete parts. So when working with something that is non-atomic, you can only be assured that it can be further divided. The classic atom is actually non-atomic since we know that it can be further split into smaller, sub-particles.
In the case of ObjC, non-atomic means that a property could be in some unexpected, intermediate stage of its setter method as its getter is called from elsewhere in the program. Thus, the getter ends up retrieving part pre-setter and part post-setter -- making it a amalgamation of code that is executed at slightly different times.
Worth mentioning is that neither atomic nor non-atomic are thread-safe because both can experience unexpected results if called on by multiple threads.
It's a bit more obvious for non-atomic properties for why this must be the case (like, what does retrieving 1/2 of an NSInteger look like?). Though much less obvious is why this is true for atomic properties.
Recall that atomic properties can exist in either a pre- or post-setter stage when called from another thread. There is no way to predict which value it will have ahead of time, and that value can change from one program execution to the next. You can only gaurantee that the value will be "whole." And because you cannot make a definite prediction on exactly when a thread will receive an atomic property's value, it is not thread-safe.
When answers regarding atomic versus nonatomic pop up, I often see the blanket response that "more code is generated for atomic properties" than nonatomic at compile time. I'm now thinking that this refers to the code that is included to ensure synchronization occurs. Synchronization refers to methods to ensure that separate threads that access the same resources do not interfere with each other. Looks like there are a number of ways of doing this, but atomic operations are advantageous because they suffer from smaller performance issues than locks (as they do not block competing threads).
This is also related to responses that include "there is less overhead for nonatomic" or "nonatomic is faster." Nonatomic operation can be performed at any time, by any thread. Atomic operations prevents such wanton execution.
A class property should be thought of as a whole, encapsulated block of code and this code includes setting the value of, and getting the value from the property.
Atomic properties guarantee that the value they provide will be whole, meaning that all of the encapsulated code for that property will have been run.
Though, whole means that the encapsulated code was wholely run before or after you requested it.
Nonatomic doesn't guarantee that the whole encapsulated code has been run by the time it is requested.
Neither is thread-safe.
Atomic: an indivisible unit.
(Atomic): indivisible (encapsulated) code block execution.
Nonatomic: able to be divisible.
(Nonatomic): partial code block execution.
To begin to understand the idea of atomic/nonatomic, I encourage reading through the following (in order):
- Threading Programming Guide (Apple)
- Synchronization (Apple)
- Atomic (Unix Manpage)
- Concurrency Programming Guide (Apple)
- The Move Away From Threads (Apple)
- Atomic vs. NonAtomic Properties (AblePear)
- Atomic vs. Nonatomic (Dephyned)
- *Optional* Atomic vs. Nonatomic Operations (Phresh)
After you read though all those, you probably can better understand the brief StackOverflow answer. At least that how it happened for me. But then again, you already know I don't like "magic."