I recently had an interview where I was asked to show how to prevent race conditions in C or C++ between two threads operating on shared data. I used a mutex as follows :
pthread_mutex_t mutex;
int shared_var = 0;
void thread1()
{
pthread_mutex_lock(&mutex); // Lock the mutex
if (shared_var == 3)
{
// do something, then decrement shared_var
shared_var--;
}
pthread_mutex_unlock(&mutex); // Unlock the mutex
}
void thread2()
{
pthread_mutex_lock(&mutex); // Lock the mutex
shared_var++;
pthread_mutex_unlock(&mutex); // Unlock the mutex
}
Then I was asked to do this in a lockless way using atomic variables instead of using a mutex.
I got stuck here a bit. Spinlocks aside, Is there a way to do this by just having shared_var an atomic variable?
At the hardware level, I guess atomic operations would use something like a compare and swap operation. If thread1 detects that shared_var == 3, but then thread2 updates shared_var by time thread1 goes to decrement it, what will happen? Will the decrement fail because thread1 detects that shared_var has since been updated? Then what? I'm generally confused as to how to implement lockless operations.