I'm working on a project, and encountered this weired problem. A detached threaded is used, and the stop flag is a boolen variable inside a structure which is passed by pointer of pointer(due to project needed). a simplified code that can produce the problem is attached here.
#include <iostream>
#include <thread>
#include <chrono>
struct weired
{
bool flag;
};
void hello_thread(void** stop)
{
weired* c = (weired*)*stop;
while (!(c->flag)) {
if (c->flag)
{
std::cout << "weired happened!, c->flag value is " << c->flag << std::endl;
break;
}
}
std::cout << "thread released" << std::endl;
}
int open(void** handle)
{
*handle = new weired;
weired* a = (weired*)*handle;
a->flag = false;
std::thread t(hello_thread, handle);
t.detach();
return 0;
}
int close(void** handle)
{
weired* a = (weired*)*handle;
a->flag = true;
delete a;
return 0;
}
int main()
{
int n;
void* handle;
n = open(&handle);
std::cin >> n;
n = close(&handle);
return 0;
}
The cin in main funciton is for waiting purpose, and when the problem happened I don't input anything, so main fucntion just stuck at cin, just before calling close() function, so the "a->flag = true;" is not executed. Considering that "std::thread t" is created after "a->flag = false;" in open() function, so when the subthread starts to run, all flag should evaluate as false, right?
The problem i encoutered is that, the subthread can enter while loop, seemed that c->flag was false, but it could aslo enter if statement and the loop was breaked, then thread quited since loop was done, so c->flag seemed to be true? but when printed its value inside if statement, the printed value was 0, still seemed that c->flag is false. then why if statement executed? weired behavior
the project is on Visual Studio Community 2019, version 16.11.29 , target is release Win32. when in debug mode, this problem doesn't happen.
i also tried the same code on linux with g++ 11.4.0. when with -O2, subthread quit at startup, seems c->flag evaluates to true. but with -O1, subthread doesn't quit. linux g++ behavior
so the compiler optimization causes this problem? Can compiler optimizes the thread creating executed before "a->flag = false; " ? but why if statement behaves so weired?
I tried replace bool with atomic<bool> type, and in this simplified code it worked, but in the real project it didn't.
Sorry for my poor English.
Having std::atomic is not always the solution for all data race problems.
What I see in your code is there are lot of read/write concurrent operations on the bool variable where the state can change any time.
What you need is some kind of locking mechanism, guard the flow until you read/write is done.