Suppose we have a function which accesses some globally shared data - and suppose this function will be called by multiple concurrent threads.
Naturally, we need to somehow synchronize access to this data. Is it possible to do this via a mechanism where we have an atomic flag, and whichever thread manages to set the flag can then proceed to access the shared data? Whereas the losing threads will not block on a lock, but simply return from the function.
Something like the following:
Given some globally shared data along with a synchronization flag:
namespace global {
int x;
int y;
std::atomic_flag sync_flag = ATOMIC_FLAG_INIT;
}
And our function which will be accessed by concurrent threads:
void race()
{
// See if we won the race
//
if (!global::sync_flag.test_and_set())
{
// We won
//
global::x = 10;
global::y = 11;
}
else
{
// We lost...
return;
}
}
Does the above code guarantee that global::x and global::y will be safely accessed by only a single thread, and that no race conditions will occur? Or is this not guaranteed due to memory ordering problems?
Note we never actually locked a mutex or anything, so no thread ends up blocking. The idea here is simply to ensure that only one thread is allowed to access (non-atomic) global variables here.
Of course, after the winning thread is done, we would need to somehow safely clear the atomic flag if we ever intend on calling race() again. That is a problem I haven't thought much about yet, but it is really beyond the scope of this question.
So is the above code race-condition free (for a single call to race())?
Yes. Only one thread can get the not-yet-set test on the flag. This has an advantage over a mutex in that on some architectures the atomic flag can be done with lock-free operations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With