Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does atomic actually mean anything for a synthesized primitive?

In Android, I could safely access and modify primitive types from different threads. I used this to share data between my OpenGL draw loop and user settings that were modified in the main thread Android UI. By storing each setting in a primitive type and making each independent of the others' values, it was thread-safe to modify all these variables without using locks or the synchronize keyword.

Is this also true in Objective-C? I read that placing atomic on a variable essentially causes the synthesized getter and setter to use locks, similar to using synchronized methods in Java. And I've read that the reason for this is so an object does not get partially modified while it's being read by another thread.

But are primitive types safe from being partially modified, as they are in Java? If that is the case, it seems like I could use my same old paradigm from Java for sharing data between threads. But then the atomic keyword would be pointless for a primitive, correct?

I also read that a more robust and faster solution than using atomic variables is to copy objects before using them if they are accessed from multiple threads. But I'm not sure how that could be accomplished. Couldn't a nonatomic object get modified while it's in the process of being copied, thereby corrupting the copy?

like image 386
Tenfour04 Avatar asked Sep 06 '13 23:09

Tenfour04


People also ask

Can Atomic be used with any data type?

atomic<> is not restricted to primitive types. It is permitted to use atomic<> with a type T that is trivially copyable.

Is Java int increment Atomic?

The most commonly used atomic variable classes in Java are AtomicInteger, AtomicLong, AtomicBoolean, and AtomicReference. These classes represent an int, long, boolean, and object reference respectively which can be atomically updated.


1 Answers

Primitive types aren't guaranteed to be safe from being partially modified because modifications to primitive types aren't guaranteed to be atomic in C and Objective-C inherits from there. C's only guarantees concern sequence points and there's no requirement that the processing between two sequence points be atomic — a rule of thumb is that each full expression is a sequence point.

In practice, modifying primitives is often a two-step process; the modification is made in a register and then written out to memory. It's very unlikely that the write itself will not be atomic but there's also no guarantee of when it will occur versus the modification. Even with the volatile qualification, the only guarantees provided are in terms of sequence points.

Apple exposes some C functions for atomic actions via OSAtomic.h that map directly to the specialised atomic instructions that CPUs offer for the implementation of concurrency mechanisms. It's possible you could use one of those more directly than via a heavy-handed mutex.

Common patterns in Objective-C are:

  • immutable objects and functional transformations — there are memory management reasons as well but that's partly why NSString, NSArray, etc, are specifically distinct from NSMutableString, NSMutableArray, etc;
  • serial dispatch queues, which can be combined with copy-modify-replace by copying on the queue, going off somewhere else to modify, then jumping back onto the queue to replace;
  • such @synchronizeds, NSConditionLocks or other explicit synchronisation mechanisms as are appropriate.

The main thread itself is a serial dispatch queue, which is why you can ignore the issue of concurrency entirely if you restrict yourself to it.

like image 119
Tommy Avatar answered Oct 16 '22 13:10

Tommy