Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is BOOL read/write atomic in Objective C?

What happens when two threads set a BOOL to YES "at the same time"?

like image 774
Jacko Avatar asked Feb 14 '10 02:02

Jacko


People also ask

Does bool need to be atomic?

You need atomic<bool> to avoid race-conditions. A race-condition occurs if two threads access the same memory location, and at least one of them is a write operation.

What is atomic in IOS Swift?

Atomic means only one thread accesses the variable (static type). Atomic is thread-safe, but it is slow. Nonatomic means multiple threads access the variable (dynamic type). Nonatomic is thread-unsafe, but it is fast. Follow this answer to receive notifications.


1 Answers

What happens when two threads set a BOOL to YES "at the same time"?

Then its value will be YES. If to threads write the same value to the same memory location, the memory location will have that value, whether that is atomic or not plays no role. It would only play a role if two threads write a different value to the same memory location or if one thread writes to it while another one is reading from it.

Is BOOL read/write atomic in Objective C?

It is if your hardware is a Macintosh running macOS. BOOL is uint32_t on PPC systems and char on Intel systems and writing these data types is atomic on their respective systems.

The Obj-C language makes no such guarantee, though. On other systems it depends on your compiler used and how BOOL is defined for that platfrom. Most compilers (gcc, clang, ...) guarantee that writing a variable of int-size is always atomic, whether other sizes are atomic depends on the CPU.

Note that atomic is not the same as thread-safe. Writing a BOOL is not a memory barrier. The compiler and the CPU may reorder instructions around a BOOL write:

a = 10;
b = YES;
c = 20;

There is no guarantee that instructions are executed in that order. The fact that b is YES does not mean that a is 10. The compiler and CPU are free to shuffle these three instructions around as desired since they don't depend on each other. Explicit atomic instructions as well as locks, mutexes and semaphores are usually memory barriers, that means they instruct the compiler and CPU to not move instructions located before that operation beyond it and not move instructions located after that operation before it (it's a hard border, that instructions may not pass).

Also cache consistency is not guaranteed. Even after you set a BOOL to YES, some other thread may still see it as NO for a limited amount of time. Memory barrier operations are usually also operations that ensure cache synchronization among all threads/cores/CPUs in the system.

And to add something really useful here as well, this is how you can ensure that setting a boolean value is atomic and acts as a memory barrier in 2020 using C11 which will also work in Obj-C Code:

#import <stdatomic.h>

// ...

volatile atomic_bool b = true;

// ...

atomic_store(&b, true);

// ...

atomic_store(&b, false);

Not only will this code guarantee atomic writes to the bool (for which the system will choose an appropriate type), it will also act as a memory barrier (Sequentially Consistent).

To read the boolean atomically from another thread, you'd use

bool x = atomic_load(&b);

You can also use atomic_load_explicit and atomic_store_explicit and pass an explicit memory order, which allows you to control more fine grained which kind of memory reordering is allowed and which ones is not.

Learn more about your possibilities here:

http://llvm.org/docs/Atomics.html

Always read "Notes for optimizers" to see which memory reordering is allowed. If in doubt, always use Sequentially Consistent (memory_order_seq_cst, which is the default if not specified). It will not result in fastest performance but it's the safest option and you really should only use something else if you know what you are doing.

like image 199
Mecki Avatar answered Oct 14 '22 10:10

Mecki