I have a RAII class that solves a problem in an inner thread:
#include <iostream>
#include <thread>
using namespace std;
struct solution_using_thread {
solution_using_thread()
: alive_(true), thread_() {
thread_ = thread([this]() {
while(alive_);
});
}
~solution_using_thread() {
alive_ = false;
thread_.join();
}
private:
bool alive_;
thread thread_;
};
int main() {
cout << 0 << endl;
try {
solution_using_thread solution;
throw 1;
} catch (int i ) {
cout << i << endl;
}
cout << 2 << endl;
}
After creating an instance of it, the main happens to throw an exception. The problem is in some of the executions, the output is:
0
when it always should have been:
0
1
2
In coliru, it is always only 0
.
What am I missing here?
PS: Sorry, for the ambiguous title. Please do not hesitate to suggest a better one for this question.
You're assuming that the thread will (eventually) see the updated value of alive_
. But that's not guaranteed. Objects without synchronisation are not guaranteed to be made visible to other threads in any finite amount of time. It's possible the value of alive_
is cached somewhere and never updated.
You need some synchronisation to make it work—either use a mutex or another synchronisation primitive, or make alive_
atomic. Here's a working example of the latter:
#include <atomic>
struct solution_using_thread {
solution_using_thread()
: alive_(true), thread_() {
thread_ = thread([this]() {
while(alive_);
});
}
~solution_using_thread() {
alive_ = false;
thread_.join();
}
private:
atomic<bool> alive_;
thread thread_;
};
Without any synchronisation, the program has Undefined Behaviour, because the two threads enter a data race over alive_
.