What is atomic?
Atomic, as describing something with the property of an atom. The word "atom" comes from the Latin atomus , which means "undivided".
I usually think that an atomic operation (regardless of language) has two qualities:
Atomic operation is always inseparable.
those. it is executed in an inseparable way, I believe that this is what the OP stands for "thread safe". In a sense, the operation occurs instantly when viewed by another stream.
For example, the following operation will most likely be split up (depends on the compiler / hardware):
i += 1;
since it can be seen by another thread (on hypothetical hardware and the compiler) as:
load r1, i; addi r1,
Two threads performing the above operation i += 1 without proper synchronization can lead to an incorrect result. Say i=0 , thread T1 loads T1.r1 = 0 , and thread T2 loads t2.r1 = 0 . Both threads increase their respective r1 by 1, and then save the result to i . Although two increments have been performed, the value of i is still only 1, because the increment operation is divisible. Note that if there was synchronization before and after i+=1 , then another thread would wait until the operation was completed, and thus would observe the whole operation.
Note that even a simple entry may or may not be indivisible:
i = 3; store i,
depending on the compiler and hardware. For example, if the address i not properly coordinated, then it is necessary to use a non-standard load / storage, which is performed by the CPU as several smaller loads / storages.
Atomic operation has guaranteed semantics of memory ordering.
Non-atomic operations may be reordered and may not necessarily be performed in the order specified in the source code of the program.
For example, in the "as-if" rule, the compiler is allowed to reorder stores and load as he sees fit as long as all access to volatile memory occurs in the order specified by the program as if the program was evaluated in accordance with the wording in the standard . Thus, non-atomic operations can be reordered, violating any assumptions about the execution order in a multi-threaded program. This is why the apparently innocent use of the raw int as a signal variable in multi-threaded programming is violated, even if the writes and reads can be indivisible, ordering can disrupt the program depending on the compiler. The atomic operation provides an ordering of operations around it depending on what semantics of memory are indicated. See std::memory_order .
The CPU can also reorder your memory accesses according to the memory limits for that CPU. You can find memory order limits for the x86 architecture in the Intel 64 and IA32 Architecture Software Developer's Guide starting on page 2212.
Primitive types ( int , char , etc.) are not Atomic
Because even if under certain conditions they may have indivisible instructions for storage and loading, or perhaps even some arithmetic instructions, they do not guarantee the storage and loading order. Therefore, they are unsafe for use in multi-threaded contexts without proper synchronization to ensure that the state of memory observed by other threads is what you think is at the moment.
Hopefully this explains why primitive types are not atomic.