6

Objective-C properties default to atomic, which ensures that accessors are atomic but doesn't ensure overall thread-safety (as per this question). My question is, aren't atomic properties redundant in most concurrency scenarios? For example:

Scenario 1: mutable properties

@interface ScaryMutableObject : NSObject {}

@property (atomic, readwrite) NSMutableArray *stuff;

@end

void doStuffWith(ScaryMutableObject *obj) {
    [_someLock lock];
    [obj.stuff addObject:something]; //the atomic getter is completely redundant and could hurt performance
    [_someLock unlock];
}

//or, alternatively
void doStuffWith(ScaryMutableObject *obj) {
    NSMutableArray *cachedStuff = obj.stuff; //the atomic getter isn't redundant
    [_someLock lock];
    [cachedStuff addObject:something]; //but is this any more performant than using a nonatomic accessor within the lock?
    [_someLock unlock];   
}

Scenario 2: immutable properties

I was thinking that maybe atomic properties would be useful for avoiding locks when working with immutable objects, but since immutable objects can point to mutable objects in Objective-C, this isn't really much help:

@interface SlightlySaferObject : NSObject {}

@property (atomic, readwrite) NSArray *stuff;

@end

void doStuffWith(SlightlySaferObject *obj) {
    [[obj.stuff objectAtIndex:0] mutateLikeCrazy];//not at all thread-safe without a lock
}

The only scenarios I can think of where it's safe to use atomic accessors without a lock (and therefore worth using atomic properties at all) are:

  1. Working with properties that are primitives;
  2. Working with properties that are guaranteed to be immutable and not to point to mutable objects (such as an NSString or an NSArray of immutable objects).

Am I missing something? Are there any other good reasons to use atomic properties?

Community
  • 1
  • 1
shosti
  • 7,107
  • 4
  • 35
  • 42
  • 1
    I think the other SO question linked by the post covers it well. atomic only covers *access* to the property -- e.g. you can't get back an int that is half-old and half-new, it'd be all-old or all-new (in the case of obj-c it also makes a guarantee on retain counts). In general, full locks/barriers may be required. However, atomic access (not CAS, which is different) can be used in some "lock-free" algorithms and/or just-get-me-out thread loops. So yes, they cover a limited bit of ground. –  Jan 14 '11 at 21:17
  • possible duplicate of [Objective-C properties: atomic vs nonatomic](http://stackoverflow.com/questions/588866/objective-c-properties-atomic-vs-nonatomic) – bbum Jan 14 '11 at 21:18
  • @pst Totally correct and there are some scalar types on some ABIs that can be partial. I think it was PPC that would put half of a particular scalar type in a register and the other half on the stack such that you could actually get half-new-half-old behavior on an otherwise single-value scalar! – bbum Jan 14 '11 at 21:20

1 Answers1

6

You aren't missing anything; atomic's usefulness is largely limited only to situations where you need to access or set a particular value from multiple threads where that value is also integral.

Beyond a single value, atomic cannot be used for thread safety purposes.

I wrote quite a bit about it in a weblog post a while ago.

This question is also a [very well posed] duplicate of What's the difference between the atomic and nonatomic attributes?

Community
  • 1
  • 1
bbum
  • 160,467
  • 23
  • 266
  • 355
  • Sorry to restart a thread 3 years later but @bbum, did you mean "where the value isn't integral" since atomicity doesn't guarantee you which value, just a legitimate value? I'm trying to understand this stuff so just asking for my clarification. – MoMo Jan 10 '15 at 02:16
  • @MoMo Right. Atomicity just guarantees integrity of the value, not whether you'll get the new or old value. And even the phrase "beyond a single value" is sometimes incorrect. On PPC, 64 bit values could sometimes be split between a 32 bit register and a 32 bit stack entry. – bbum Jan 12 '15 at 17:38