6

Sometimes we have a simple readOnly Property whose value may change

@property (readonly) NSFetchedResultsController * FetchController;
@property (readonly) NSFetchRequest * FetchRequest;
@property (readonly) NSPredicate * KeywordPredicate;

I suppose when the value change it's done on a blink of an eye through some sort of simple pointer manipulation. Something like

_FetchRequest = newFetchRequest;

The actual process of changing may change a lot but the actual change should be on that one line.

The question is, is such simple pointer assignment always atomic? What about if that one line actually consist of several line of machine codes and somebody ask for the property between those machine codes?

At the end the question is whether simple assignment operator on pointers is always atomic or not.

If so, when it is atomic and what's not? Simple assignment operators won't be atomic for complex objects of course.

So to what extend those simple one line assignment operators are atomic? For pointers and primitive types, will it always be?

Anonymous White
  • 2,149
  • 3
  • 20
  • 27
  • You'll probably also find my answer (and the subsequent comments) on this relevant. http://stackoverflow.com/questions/588866/atomic-vs-nonatomic-properties/589392#589392 – bbum Oct 19 '12 at 23:57

2 Answers2

5

It is a common misconception to consider read-only operations as atomic in nature. It isn't guaranteed. It is also a common misconception that atomicity guarantees thread safety, but that is a different subject.

The difference between atomic and nonatomic on readonly properties is that atomic (which is the default, but not declared) guarantees that the value returned from the readonly retrieval method is integral.

That is, if it is an object, it will be retained and autoreleased. If it is a struct, an appropriate lock will have been used to ensure an integral value of the struct was returned.

Note that simply because a property is declared publicly readonly does not preclude it being re-declared as readwrite for internal use. Thus, the difference between atomic and nonatomic might be quite significant; a class might declare a readonly property as nonatomic while also documenting that all API on the class must be used from one thread only.

Community
  • 1
  • 1
bbum
  • 162,346
  • 23
  • 271
  • 359
  • Good. So I should still declare my readonly operation as atomic to ensure things do not go wrong. However, the result returned by atomic will always be valid then and that's good enough. – Anonymous White Oct 19 '12 at 08:42
  • Both answers are good. +1 for both. Still don't know which one to select :) – Anonymous White Oct 19 '12 at 08:42
  • For more on [Atomicity guarantees thread safety](http://stackoverflow.com/questions/12347236/which-is-threadsafe-atomic-or-non-atomic) – Anoop Vaidya Mar 17 '14 at 07:13
4

I think you're misunderstanding what atomic (or more appropriately, nonatomic) means in this context. The simplest explanation can be found in objc-accessors.mm itself:

id objc_getProperty_non_gc(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
    // Retain release world
    id *slot = (id*) ((char*)self + offset);
    if (!atomic) return *slot;

    // Atomic retain release world
    spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
    _spin_lock(slotlock);
    id value = objc_retain(*slot);
    _spin_unlock(slotlock);

    // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
    return objc_autoreleaseReturnValue(value);
}

As you can see, atomicity here refers only to the validity of the returned object. It it retained and autoreleased in order to guarantee that it does not get deallocated while you are using it.

If this [[obj retain] autorelease] was not performed, another thread could set the property, which would cause the previous property (i.e. the one you're using) to be released and possibly deallocated.

Aidan Steele
  • 10,999
  • 6
  • 38
  • 59
  • 1
    On iOS, any non-retainable property over 32 bits is handled by `objc_copyStruct` (also in `objc-accessors.mm`). Any non-retainable property 32 bits or smaller is handled inline with no locking (but with a memory barrier if targeting a device). Tested with Xcode 4.5.1. – rob mayoff Oct 19 '12 at 05:52
  • oh so that's the difference between atomic and atomic. The result returned is retained and autoreleased. That is all. So that means readOnly property is as vulnerable as readwrite property then. It may be non atomic then? It may change depending on the internal structure of the code. – Anonymous White Oct 19 '12 at 06:22
  • And that means assigning things to double or long is not inherently atomic too? Am I correct here? I mean iOs is 64 bit right? Why the strange limitation? Or what am I missing? – Anonymous White Oct 19 '12 at 06:23
  • why use .mm file as your sample? I thought objective-c is build on c, not C++ – Anonymous White Oct 19 '12 at 06:23
  • 1
    @haryanto-ciu that code is not an example but is from the implementation of the property lookup itself in the objective-c runtime which is publicly available at opensource.apple.com. It's an Objective-C++ file. – NeedTungsten Nov 06 '12 at 19:37
  • "another thread could set the property" - not when it is `readonly` and that is what the question is all about. And with readonly I mean really readonly. If made internally `readwrite` it isn't really readonly, that's only what the public interface makes you think it is. – Mecki Mar 18 '21 at 02:09