2

atomic keyword is applied to properties of a class, for thread safety.

Usage of atomic is thread safe for primitive data types but not the complex objects (modal objects). Why ?

Thanks in advance for the kind reply!

Update

If Person is a Class having properties name, age, address.

Consider

@property(atomic, strong) Person *adam;

How far is the object adam thread safe ?

user3460006
  • 112
  • 9
  • 2
    I don't think this is an exact duplicate of the above linked question. I suspect a reason why atomic might not be safe for a complex object would be if that object has its own `nonatomic` properties. Either way, I'd love to see an explicit answer for this question (as I just got burned hard on a recent job interview when I wasn't able to answer a question along these lines quickly or authoritatively enough). – Michael Dautermann Mar 28 '17 at 12:56
  • 1
    What do you mean with "complex objects"? All properties store "primitive data" types. Please, keep in mind that references are stored, not objects. – Amin Negm-Awad Mar 28 '17 at 13:27
  • @MichaelDautermann Not quite a duplicate, but now it is as I added an explicit example. The discussion in there as to why *atomic does not mean thread safe* holds to complex objects, too. Basically, any time you have more than one property that must be maintained in sync, then atomicity of a single property is not sufficient to achieve thread safety. – bbum Mar 28 '17 at 16:48

2 Answers2

2

This is really a dupe of What's the difference between the atomic and nonatomic attributes? even prior to the edit, though it wasn't obvious.

Since that answer is referred to often, I added the following to underscore that thread safety is really all about having some kind of a transactional model where the reads and writes are controlled such that the system is in a known, integral, state when a read or write happens.

atomicity of a single property also cannot guarantee thread safety when multiple dependent properties are in play.

Consider:

 @property(atomic, copy) NSString *firstName;
 @property(atomic, copy) NSString *lastName;
 @property(readonly, atomic, copy) NSString *fullName;

In this case, thread A could be renaming the object by calling setFirstName: and then calling setLastName:. In the meantime, thread B may call fullName in between thread A's two calls and will receive the new first name coupled with the old last name.

To address this, you need a transactional model. I.e. some other kind of synchronization and/or exclusion that allows one to exclude access to fullName while the dependent properties are being updated.

Community
  • 1
  • 1
bbum
  • 160,467
  • 23
  • 266
  • 355
2

The difference stems from the fact that an object comes with its own methods and behaviour, which could cause changes to the object outside of its setter and getter.

Atomic keyword provides thread synchronisation only between the setter and getter that the compiler synthesizes.

This is generally sufficient to provide thread safety to a primitive property, as its underlying ivar is only accessed via its setter and getter.

However, for an object property this would only provide thread safety for the pointer to the object. The setter and getter would be synchronized themselves, but some other method of that object may be modifying it from a different thread and the property will not be thread safe overall. If you want to make it safe you'll have to implement synchronisation with all methods that have the potential to modify the object.

For example, the following immutable string should be thread safe because it is only modified via accessors

@property (atomic, strong) NSString * immutableString;

While the following mutable one will not be thread safe

@property (atomic, strong) NSMutabeString * mutableString;
Sulevus
  • 619
  • 5
  • 13