The basic idea

In a normal scenario where 2 different threads operate on the same value, something like this may happen:

x = 0

// Thread 1
x = 1

// Thread 2
cout << x << endl;

Suppose Thread 1 goes first, then Thread 2. Then we expect to get 1 printed, with x = 1 at the end.

However, it is not guaranteed that x = 1 compiles to one instruction, this depends on the architecture (e.g. 64-bit instructions might become 2 32-bit instructions on 32 bit platforms). OR even that the instructions execute atomically on the processor (e.g. ARMv7 - STRD instruction).

As a result, instruction from thread 2 could run while instruction from thread 1 is mid-way. This will corrupt the read result from thread 2.

To avoid these behaviours we use atomics. They ensure that mid-way while either instruction occurs, no other conflicting instruction can intervene (unless they are both reads of course).

More goodies

This form of synchronization follows the rule of Sequential Consistency Instructions interleave in some sequence. Whatever this sequence is, all threads have to agree on.

See Memory orders for more strategies we can choose.