Search code examples
objective-cmultithreadingatomicdeclared-property

Am I missing any points in my argument in favor of atomic properties?


I read this question (and several others):

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

I fully understand (at least I hope so :-D ) how the atomic/nonatomic specifier for properties works:

  1. Atomic guarantees that a "read" operation won't be interrupted by a "write" operation. Nonatomic doesn't guarantee this.

  2. Neither atomic nor nonatomic solve race conditions, where one thread is reading and two threads are writing. There is no way to predict what result the read operation will return. This needs to be solved by additional synchronization.

  3. Neither atomic nor nonatomic guarantee overall data integrity; one thread could set one property while another thread sets a second property in a state which is inconsistent with the state of the first property. This also needs to be solved by additional synchronization.

What make my eyebrow raise is that people are divided into two camps:

Pro atomic: It make sense to use nonatomic only for performance optimization.

And if you are not optimizing, then you should always use atomic because of point 1. This way you won't get some complete crap when reading this property in a multi-threaded application. And sure, if you care about points 2 and 3, you need to add more synchronizaion on top of it.

Against atomic: It doesn't make sense to use atomic at all.

Since atomic doesn't solve all the problems in a multi-threaded application, it doesn't make sense to use it at all, since you will need to add more synchronization code on top of it anyway. It will just make things slower.

I am leaning to the pro-atomic camp, but I want to do a sanity check that I didn't miss anything.


Solution

  • Lacking a very specific question (though still a good question), I'll answer with personal experience, FWIW.

    In general, concurrency design is hard. With modern conveniences like GCD and ARC, the tools for implementing concurrent systems have certainly improved. However, the architecture of concurrency is still very hard.

    And, generally, the hard part has nothing to do with individual properties; individual getters and setters. Concurrency is something that is implemented at a higher level.

    The current state of the art is concurrency in isolation. That is, the parts of your app that are running concurrently are doing so using isolated graphs of objects that have extremely minimal connection to the rest of your application (typically, the "connections" are via callbacks that bundle up a bit of state and toss it over to some other queue, often the main queue for updating the UI).

    By keeping the concurrency surface area -- the # of entry points into your code that must be concurrency safe -- to an absolute minimum, you reduce both complexity and the amount of time you'll spend debugging really weird, oft irreproducible, concurrency problems (that'll eat at your sanity).

    Given all that, the value of atomic properties is pretty minimal. Sure, they can be useful along what should be the very very small set of interfaces -- of API -- that might be banged upon from multiple threads, but that is about it.

    If you have objects for which the accessors are being banged on rapidly, making them atomic can be a significant performance hit, but premature optimization is the devil's fingers at play.