views:

31358

answers:

4

What do atomic and nonatomic mean in property declarations?

@property(nonatomic, retain) UITextField *userName;

@property(atomic, retain) UITextField *userName;

@property(retain) UITextField *userName;

What is the functional difference between these 3?

+1  A: 

Atomic guarantees that access to the property will be performed in an atomic manner. E.g. it will be thread safe, any get/set of a property on one thread must complete before another can access it.

If you imagine the following function occurring on two threads at once you can see why the results would not be pretty.

-(void) setName:(NSString*)string
{
  if (name)
  {
    [name release]; 
    // what happens if the second thread jumps in now !?
    // name may be deleted, but our 'name' variable is still set!
    name = nil;
  }

  ...
}
Andrew Grant
It won't be thread safe. Atomicity only guarantees that you get a value that is whole -- which may not be the same as the value currently in the object. Atomicity does not generally contribute to thread safety.
bbum
That comment doesn't make a lot of sense. Can you clarify? If you look at examples on the Apple site then the atomic keyword synchronizes on the object while updating its properties.
Andrew Grant
Sure; thread safety can only be really expressed at the model level, not the individual accessor. Think of firstName/lastName, thread A retrieves firstName, thread B sets lastName, thread A retrieves lasName, thread B sets firstName. A now has a mismatched set of names; atomicity can't protect against that without introducing transaction atomicity which is a model level issue.
bbum
+7  A: 

Easiest answer first: There's no difference between your second two examples. By default, property accessors are atomic.

Atomic accessors in a non garbage collected environment (i.e. when using retain/release/autorelease) will use a lock to ensure that another thread doesn't interfere with the correct setting/getting of the value.

See the "Performance and Threading" section of Apple's Objective-C 2.0 documentation for some more information and for other considerations when creating multi-threaded apps.

Jay O'Conor
So why would I want to specifically make something nonatomic?
Squeegy
Two reasons. First off, for synthesized code it generates faster (but not threadsafe code). Second, if you are writing customer accessors that are not atomic it lets you annotate for any future user that the code is not atomic when they are reading its interface, without making them implementation.
Louis Gerbarg
+37  A: 

This is explained in Apple's documentation, but below are some examples of what is actually happening. Note that there is no "atomic" keyword, if you do not specify "nonatomic" then the property is atomic, but specifying "atomic" explicitly will result in an error.

//@property(nonatomic, retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    return userName;
}

- (void) setUserName:(UITextField *)userName_ {
    [userName_ retain];
    [userName release];
    userName = userName_;
}

Now, the atomic variant is a bit more complicates:

//@property(retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    UITextField *retval = nil;
    @synchronized(self) {
        retval = [[userName retain] autorelease];
    }
    return retval;
}

- (void) setUserName:(UITextField *)userName_ {
    @synchronized(self) {
      [userName_ retain];
      [userName release];
      userName = userName_;
    }
}

Basically, the atomic version has to take a lock in order to guarantee thread safety, and also is bumping the ref count on the object (and the autorelease count to balance it) so that the object is guaranteed to exist for the caller, otherwise there is a potential race condition if another thread is setting the value, causing the ref count to drop to 0.

There are actually a large number of different variants of how these things work depending on whether the properties are scalar values or objects, and how retain, copy, readonly, nonatomic, etc interact. In general the property synthesizers just know how to do the "right thing" for all combinations.

Louis Gerbarg
Not that the lock doesn't "guarantee thread safety".
Jonathan Sterling
Thread safety in the sense that concurrent accesses on multiple threads will not cause corruption due to retain/release (malloc/free) issues will using the accessors. Obviously it doesn't (and can't) guarantee safety with respect to the semantics of a particular object returned by the accessor.
Louis Gerbarg
I just noticed that about 6 months ago someone edited my answer, and replaced the code with incorrect code, I have rolled it back. For reference, the nonatomic accessor DOES NOT need to retain/autorelease its return value since it does not need to worry that another thread is tweaking the retain count. This is one of the primary efficiency gains of declaring something nonatomic. If you are going to edit someone else's answers in code, please make sure you actually know what you are doing.
Louis Gerbarg
@Louis Gerbarg: I believe your version of the (nonatomic, retain) setter will not work properly if you try to assign the same object (that is: userName == userName_)
Florin
It depends on whether or not there is an outside retain. I claim that in all but the most trivial cases it is a non-issue because if you are using an object you must either show an interest in it (by retaining it) or know that an underlying object you have retained also retains it (an array, dict, etc). Resetting the property to itself without retaining it inbetween violates that. Having said that, I can alter the setter to accommodate that. Just to be clear, that was not what I was complaining about, the changes that annoyed me were straight up incorrect alterations to the nonatomic getter.
Louis Gerbarg
+88  A: 

The last two are identical; 'atomic' is the default behavior.

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.

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.

bbum
It just occured to me that if you provide data integrity, atomicity of properties is not required, as you'll only have one thread writing to a property at any one time (during which time no reads are allowed either). Am I right in thinking this?
Toon Van Acker
That would generally be correct. Example; if you were to manage access to a sub-graph of objects such that the sub-graph is only ever interacted with on a single thread, all properties used on that sub-graph can be nonatomic.
bbum