What's the Difference Between the Atomic and Nonatomic Attributes

What's the difference between the atomic and nonatomic attributes?

The last two are identical; "atomic" is the default behavior (note that it is not actually a keyword; it is specified only by the absence of nonatomic -- atomic was added as a keyword in recent versions of llvm/clang).

Assuming that you are @synthesizing the method implementations, atomic vs. non-atomic changes the generated code. If you are writing your own setter/getters, atomic/nonatomic/retain/assign/copy are merely advisory. (Note: @synthesize is now the default behavior in recent versions of LLVM. There is also no need to declare instance variables; they will be synthesized automatically, too, and will have an _ prepended to their name to prevent accidental direct access).

With "atomic", the synthesized setter/getter 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. That is, if thread A is in the middle of the getter while thread B calls the setter, an actual viable value -- an autoreleased object, most likely -- will be returned to the caller in A.

In nonatomic, no such guarantees are made. Thus, nonatomic is considerably faster than "atomic".

What "atomic" does not do is make any guarantees about thread safety. If thread A is calling the getter simultaneously with thread B and C calling the setter with different values, thread A may get any one of the three values returned -- the one prior to any setters being called or either of the values passed into the setters in B and C. Likewise, the object may end up with the value from B or C, no way to tell.

Ensuring data integrity -- one of the primary challenges of multi-threaded programming -- is achieved by other means.

Adding to this:

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.

What's the difference between 'atomic' and non-atomic?

Atomic properties are necessary in a reference counted multi threaded environment in order to stop objects from disappearing before a thread has a chance to retain them.

Consider the naive implementation of a get accessor:

@interface MyObject : NSObject 
{
id myPropertyIVar;
}
-(id) myProperty;

@end

@implementation MyObject

-(id) myProperty
{
return myPropertyIvar;
}

// other stuff

@end

This is all fine except that if you release the instance of MyObject before retaining the returned value from -myProperty the returned value may well be deallocated. For this reason, it is safer to implement -myProperty like this:

-(id) myProperty
{
return [[myPropertyIvar retain] autorelease];
}

This is now completely safe in a single threaded environment.

Unfortunately, in a multithreaded environment there is a race condition. If the thread is interrupted at any time before the retain has incremented the retain count, either of the following will cause you to receive a garbage pointer:

  • the instance of MyObject is released and deallocated by another thread causing the ivar to be released and deallocated
  • myProperty is reassigned by another thread causing the old version to be released and deallocated

For this reason, all accesses to the property must be protected by a lock. The get accessor looks something like this.

-(id) myProperty
{
// lock
return [[myPropertyIvar retain] autorelease];
// unlock
}

The set accessor is similarly protected and so is the release in -dealloc

What does the property Nonatomic mean?

Take a look at the Apple Docs.

Basically, if you say nonatomic, and you generate the accessors using @synthesize, then if multiple threads try to change/read the property at once, badness can happen. You can get partially-written values or over-released/retained objects, which can easily lead to crashes. (This is potentially a lot faster than an atomic accessor, though.)

If you use the default (which is atomic; there used to be no keyword for this, but there is now), then the @synthesized methods use an object-level lock to ensure that multiple reads/writes to a single property are serialized. As the Apple docs point out, this doesn't mean the whole object is thread-safe, but the individual property reads/writes are.

Of course, if you implement your own accessors rather than using @synthesize, I think these declarations do nothing except express your intent as to whether the property is implemented in a threadsafe manner.

Do atomic and nonatomic attributes on properties have any effect if you use a custom getter/setter?

Does the atomic attribute on the property declaration actually do anything? Or is it only used if an automatic getter/setter is actually created by the compiler?

atomic is used only when a getter/setter is synthesized by the compiler. It is also used to check the consistency of accessors for readwrite properties:

Because the internal implementation and synchronization of atomic accessor methods is private, it’s not possible to combine a synthesized accessor with an accessor method that you implement yourself. You’ll get a compiler warning if you try, for example, to provide a custom setter for an atomic, readwrite property but leave the compiler to synthesize the getter.



is there any convention for what attribute we should use for those properties?

Apple does not require you to follow any convention, but you could use atomic and nonatomic attributes to document your own code. This would let readers of your code learn about the behavior of your accessors without looking into their implementation.

When to use @atomic?

The typical use-case for atomic properties is when dealing with a primitive data type across multiple threads. For example, let's say you have some background thread doing some processing and you have some BOOL state property, e.g. isProcessComplete and your main thread wants to check to see if the background process is complete:

if (self.isProcessComplete) {
// Do something
}

In this case, declaring this property as atomic allows us to use/update this property across multiple threads without any more complicated synchronization mechanism because:

  • we're dealing with a scalar, primitive data type, e.g. BOOL;
  • we declared it to be atomic; and
  • we're using the accessor method (e.g. self.) rather than accessing the ivar directly.

When dealing with objects or other more complicated situations, atomic generally is insufficient. As you point out, in practice, atomic, alone, is rarely sufficient to achieve thread safety, which is why we don't use it very often. But for simple, stand-alone, primitive data types, atomic can be an easy way to ensure safe access across multiple threads.

What's the difference between the atomic and nonatomic attributes?

The last two are identical; "atomic" is the default behavior (note that it is not actually a keyword; it is specified only by the absence of nonatomic -- atomic was added as a keyword in recent versions of llvm/clang).

Assuming that you are @synthesizing the method implementations, atomic vs. non-atomic changes the generated code. If you are writing your own setter/getters, atomic/nonatomic/retain/assign/copy are merely advisory. (Note: @synthesize is now the default behavior in recent versions of LLVM. There is also no need to declare instance variables; they will be synthesized automatically, too, and will have an _ prepended to their name to prevent accidental direct access).

With "atomic", the synthesized setter/getter 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. That is, if thread A is in the middle of the getter while thread B calls the setter, an actual viable value -- an autoreleased object, most likely -- will be returned to the caller in A.

In nonatomic, no such guarantees are made. Thus, nonatomic is considerably faster than "atomic".

What "atomic" does not do is make any guarantees about thread safety. If thread A is calling the getter simultaneously with thread B and C calling the setter with different values, thread A may get any one of the three values returned -- the one prior to any setters being called or either of the values passed into the setters in B and C. Likewise, the object may end up with the value from B or C, no way to tell.

Ensuring data integrity -- one of the primary challenges of multi-threaded programming -- is achieved by other means.

Adding to this:

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.

Using NSLocks as atomic or non atomic properties?

atomic makes setting and getting the property atomic, if the property doesn't need to be accessed atomically, maybe its only reads from multiple threads after if as been set, then it doesn't need to be atomic.
Alternatively, how often is this property going to be called, you would need to call it pretty often in a loop to notice the effect of the property being atomic. you can also do things like call the property only once in a method and keep a local reference to it to reduce the overhead of it being atomic.

For properties, if there is any doubt I about whether it needs to be atomic or not, I usually make them atomic, if that creates a performance problem I can look at dealing with that later, but having a bug introduced because of a nonatomic property, is much more serious issue.

What is the difference of these @properties in Objective c?

retain and atomic/nonatomic are orthogonal, meaning that any combination of them is valid. retain says that there is a strong link between the object and its retained property (i.e. the object referenced by the property should not be released while it is pointed to by this object). atomic/nonatomic means that the access to the property should or should not be synchronized. Here is a great explanation of the atomic/nonatomic.

Note that all of this is meaningful only when you use @synthesize.



Related Topics



Leave a reply



Submit