Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing a 64-bit variable in different threads without synchronization or atomicity

I have two threads sharing an uint64_t variable. The first thread just reads from the variable while the other thread just writes into. If I don't synchronize them using mutex/spinlock/atomic operations etc.., is there any possibility of reading another value from the writing thread wrote into? It is not important to read an old-value which was written by writing thread.

As an example, the writing thread increases the variable between 0 and 100, and the reading thread prints the value. So, is there any possibility to see a value in the screen different than [0-100] range. Currently I don't see any different value but I'm not sure it can cause a race condition.

Thanks in advance.

like image 896
avatli Avatar asked Feb 01 '18 11:02

avatli


2 Answers

On a 64 bit processor, the data transfers are 64 bits at a time, so you will see logically consistent values i.e. you won't see 32 bits from before the write and 32 bits after the write. This is obviously not true of 32 bit processors.

The kind of issues you will see are things like, if the two threads are running on different cores, the reading thread will not see changes made by the writing thread until the writing thread's core flushes its cache. Also, optimisation may make either thread not bother to read memory at all in the loop. For example, if you have:

uint64_t x = 0;

void increment()
{
    for (int i = 0 ; i < 100 ; ++i)
    {
        x++;
    }
}

It is possible that the compiler will generate code that reads x into a register at the start of the loop and not write it back to memory until the loop exits. You need things like volatile and memory barriers.

like image 141
JeremyP Avatar answered Nov 02 '22 18:11

JeremyP


All bad things can happen if you have a race condition on such a variable.

The correct tool with modern C for this are atomics. Just declare your variable

uint64_t _Atomic counter;

Then, all your operations (load, store, increment...) will be atomic, that is indivisible, uninterruptible and linearizable. No mutex or other protection mechanism is necessary.

This has been introduced in C11, and recent C compilers e.g gcc and clang, now support this out of the box.

like image 22
Jens Gustedt Avatar answered Nov 02 '22 17:11

Jens Gustedt