There are several layers to this.
First, a declared property is mostly just a shortcut to declaring accessor methods. Compiler synthesis of the property, which happens by default if you don't provide your own implementation, defines those methods and an instance variable to back the property.
So, this:
@property(atomic,assign) NSInteger sum;
is basically just this:
- (NSInteger) sum;
- (void) setSum:(NSInteger)value;
Synthesis of the property produces an instance variable and implementations of those methods:
@implementation ...
{
NSUInteger _sum;
}
- (NSInteger) sum
{
// ...
}
- (void) setSum:(NSInteger)value
{
// ...
}
For an atomic property, the implementations of -sum
and -setSum:
are each guaranteed to operate such that neither can appear to interrupt the other. A call to -sum
that happens "simultaneously" with a call to -setSum:
will either return the value before -setSum:
or the value after it, but never some frankenstein value that's partially modified or any interim value. Likewise, two simultaneous calls to -setSum:
will result in _sum
having the value from one or the other of those calls, but never some mix or interim value. That is the two calls will seem to have happened in a strict order, either A then B or B then A, arbitrarily.
This is easier to understand for a property with a compound type, such as NSRect
. Two threads setting the property will never result in, for example, the origin
from one thread and the size
from another thread being stored. One or the other will "win" and the rect will be coherent. Likewise, a thread calling the getter will never see a mixed value even if it happens simultaneously with a call to the setter.
Next, accesses to the property using dot syntax (e.g. self.sum
) are really just a shortcut for calling the accessors. Since there are only get and set accessors, and not any "increment" accessor, a statement like self.sum++;
needs to do both, separately:
[self setSum:[self sum] + 1];
So, your statement involves first a call -sum
then a call to -setSum:
for each thread. There's nothing that ensures that other threads can't interleave their operations with each other. The property's atomicity doesn't prevent it. That is, thread A may get the value 5 from its call to -sum
, thread B may also get the value 5 from its call to -sum
, each may calculate 6 as the new value, then they both call -setSum:
with the value 6. So two threads will have "incremented" the property, but it will only have increased by 1.
In short, atomicity is not thread-safety. It's a conceptual mistake to think that it is. It's just atomicity. It does prevent one kind of corruption that can happen when multiple threads simultaneously access the same property, but not all kinds.
dispatch_queue_t queue = dispatch_queue_create...
to before the loop. You must not create a new queue for each loop iteration. Only thedispatch_async
should be inside the loop. – rmaddy