The following program is giving me unexpected behavior when it's printing the "bad" output once in a while. The two threads are supposed to synchronize using the two std::atomic variables 's_lock1' and 's_lock2'. In func2, in order to set the 's_var' variable to 1, it must have atomically stored a non-zero value in 's_lock2' and the other thread (func1) must not have updated the 's_lock1' variable yet. However, somehow in func1 it's printing the unexpected "bad" output. The s_lock2.load() statement seems to return false instead. Is there something wrong with this code snippet? Is it an issue related to memory ordering?
I am running this on an 8-core Linux server with Centos 7 installed. Any help is greatly appreciated.
#include <iostream>
#include <thread>
#include <atomic>
#include <unistd.h>
std::atomic_uint s_lock1 = 0;
std::atomic_uint s_lock2 = 0;
std::atomic_uint s_var = 0;
static void func1()
{
while (true) {
s_lock1.store(1, std::memory_order_release);
if (s_lock2.load(std::memory_order_acquire) != 0) {
s_lock1.store(0, std::memory_order_release);
continue;
}
if (s_var.load(std::memory_order_acquire) > 0) {
printf("bad\n");
}
usleep(1000);
s_lock1.store(0, std::memory_order_release);
}
}
static void func2()
{
while (true) {
s_lock2.store(1, std::memory_order_release);
if (s_lock1.load(std::memory_order_acquire) != 0) {
s_lock2.store(0, std::memory_order_release);
continue;
}
s_var.store(1, std::memory_order_release);
usleep(5000);
s_var.store(0, std::memory_order_release);
s_lock2.store(0, std::memory_order_release);
}
}
int main()
{
std::thread t1(func1);
std::thread t2(func2);
t1.join();
t2.join();
}