37

In my few years as an iOS developer I don't think I've ever used atomic on a property. If I can see potential race conditions or data integrity issues due to threading, using atomic on a @property wouldn't ever help. I use conventional transaction/unit-of-work thread safety techniques (using mechanisms locks, semaphores or whatever).

Does anyone have (or know of) any practical examples of where atomic is used? (I'd love to see some actual/practical code examples)

After writing nonatomic for maybe the billionth time, I'm also wondering why Apple have decided to make atomic the default.

Lebyrt
  • 1,398
  • 1
  • 9
  • 18
CVertex
  • 17,451
  • 27
  • 88
  • 124
  • 2
    @Joe I guess safety by default was their grounds.. so I guess i'm never safe :/ – CVertex Mar 30 '11 at 12:20
  • @Joe was it a resource contention bug? – CVertex Mar 31 '11 at 05:48
  • So how much of a performance hit does it really have on real world applications? I'm willing to sacrifice a certain degree of performance if it means I might otherwise have to spend x weeks pulling my hair out trying to debug issues arising from this (and potentially keeping end users waiting for a fix). If the performance difference is barely noticeable to end users, why not default to atomic? – Brad Thomas Nov 23 '13 at 17:13

5 Answers5

22

As for the first problem you're having, maybe it's because

Although “atomic” means that access to the property is thread-safe, simply making all the properties in your class atomic does not mean that your class or more generally your object graph is “thread safe”—thread safety cannot be expressed at the level of individual accessor methods.

As for why apple makes it atomic by default, I don't think there is any good reason, it was simply a bad design decision. Guys at the WWDC sessions repeatedly encouraged people to use nonatomic wherever you can to eliminate the performance impact.

Tomas Vana
  • 16,537
  • 9
  • 51
  • 62
  • 1
    It is also likely that you're programming on the iPhone. On the Mac you're more likely to have multi-threaded programs, where the performance hit is not as noticeable. – Stephen Furlani Mar 02 '11 at 13:58
  • 3
    +1 for identifying it as a bad design decision and also stating that atomic isn't a silver bullet for thread safety. – CVertex Mar 03 '11 at 07:10
  • This should be a compiler setting. I ended up making property macros for various types (strong, copy, assign, weak) that put in the non-atomic. – jjxtra Dec 31 '13 at 17:47
  • "it was simply a bad decision" ... That's a bit strong. We don't need it often, but when we do, it's very useful. I'd characterize the "atomic by default" decision as an overly cautious design. Apple seems to have made up for this by not having atomic properties at all in Swift (which makes it a PITA when you really need atomic behavior). – Rob Jun 09 '17 at 17:51
10

It's worth noting that under garbage collection, almost all synthesized accessors are inherently atomic—there would be no difference between the atomic and nonatomic version, since the simple assignment of a pointer is all that's required in both cases. Since you really can't make a nonatomic synthesized accessor under garbage collection, they may have decided that it made more sense to just have things atomic by default.

I don't have any evidence that this was the reasoning behind the decision, but it makes sense to me.

(In case you're curious, there are still cases under garbage collection where simple assignment is nonatomic—this happens when the value is larger than the word size of the process. In practice, that only happens with structs.)

Edit: Added sources

More information on the atomicity of synthesized properties under garbage collection can be found in The Objective-C Programming Language -> Declared Properties -> Performance and Threading, where it says "In a garbage collected environment, most synthesized methods are atomic without incurring this overhead." The inherent atomicity is mentioned more explicitly in the 2008 WWDC session 420 "Using Garbage Collection with Objective-C", around the 29 minute mark.

BJ Homer
  • 47,750
  • 10
  • 111
  • 128
4

In two words - thread safety. Most of the applications we write on a regular basis are fairly simple and as such are actually going to benefit from not having the additional locks.


From Apple's The Objective-C Programming Language:

Properties are atomic by default so that synthesized accessors provide robust access to properties in a multi-threaded environment—that is, the value returned from the getter or set via the setter is always fully retrieved or set regardless of what other threads are executing concurrently. For more details, see “Performance and Threading.”

If you do not specify nonatomic, then in a reference counted environment a synthesized get accessor for an object property uses a lock and retains and autoreleases the returned value—the implementation will be similar to the following:

[_internal lock]; // lock using an object-level lock
id result = [[value retain] autorelease];
[_internal unlock];
return result;

If you specify nonatomic, then a synthesized accessor for an object property simply returns the value directly.

ennalax
  • 196
  • 3
3

When Apple first introduced the concept of properties, there was a big argument about whether atomic or nonatomic should be the default and the atomic people won.

I think the reasoning is that in a threaded environment, unless the property is atomic, you can't guarantee that the pointer it returns is valid. A non atomic getter would be implemented something like this

-(MyObj*) someProperty
{
     return someInstVar;
}

It's possible that some other thread could deallocate the object pointed to by someInstVar after the pointer has been placed in the register for returning but before the caller has had time to retain it. Even this is no good:

-(MyObj*) someProperty
{
     return [[someInstVar retain] autorelease];
}

because some other thread could dealloc someInstVar just before the retain count is incremented.

The only way to safely return the pointer in a multithreaded environment is something like this:

-(MyObj*) someProperty
{
     @synchronized(self)
     {
         return [[someInstVar retain] autorelease];
     }
}

and also to synchronise the setter too.

However, the problem with that is that the lock is very expensive (in reality they used something much lighter than @synchronized but it's still expensive) so everybody was using nonatomic anyway and just making all the properties atomic doesn't confer thread safety in general so other techniques are required anyway and they tend to obviate the problem I discussed above.

There are plenty of people who think the wrong decision was made about what the default should be, but it can't be changed now for backwards compatibility. I find myself typing nonatomic without even thinking now.

JeremyP
  • 80,230
  • 15
  • 117
  • 158
2

Atomic calls are calls that cannot be interrupted. The entire call must be executed.

Updating something like a shared counter variable would be something that could be atomic because you wouldn't want two processes trying to access the variable at the same time. The actions would need to be executed "atomically".

There is a lot of useful information in this SO post: Atomic vs nonatomic properties as to what the differences are and the thread safety issues of atomic vs nonatomic.

Community
  • 1
  • 1
Larry Hipp
  • 5,945
  • 3
  • 24
  • 29
  • 2
    -1 for not answering the question. He understands what `atomic` does and what it's for, he was asking whether there's a good reason for it to be the default. – Mark Amery Aug 16 '13 at 15:35
  • I answered "Does anyone have (or know of) any practical examples of where atomic is used?" with an example of a shared counter variable. – Larry Hipp Aug 16 '13 at 15:40
  • You're quite right - my apologies. You may not have answered the question in the title, or the one I came here for, but it was a totally legitimate answer to one of the questions in the question body (and partial answers are, as far as I know, welcomed - I certainly have no problem with this one). I've retracted my downvote. – Mark Amery Aug 16 '13 at 15:43