I recently asked "Thrown object cannot be caught in a multi-threaded solution" and got the correct answer which works perfectly. However, I am still confused why there can be a race condition when only one thread does the write operation. Let me paste the original problematic code:
#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;
}
Sometimes the output is only
0
According to the linked question, if I instead use member atomic<bool> alive_
, the output becomes as expected
0
1
2
Now, I am trying to reason why member bool alive_
causes Undefined Behavior.
Case 1 (Happy ending):
- Variable
solution
is initialized:solution_using_thread
's default constructor setsalive_
totrue
in the main thread.- The thread starts and the value of
alive_
happens to betrue
in the second thread. So thread execution is stuck in thewhile
loop. - Before constructor returns, the second thread has already been started.
- We
throw 1
.- The destructor of
solution
is called. The value ofalive_
istrue
in the main thread. thread.join()
blocks until the value ofalive_
is synchronized with the second thread.- After some finite amount of delay
alive_
is synchronized, the while loop terminates, the second thread finishes, thethread_.join()
returns and stack unwinding is happily completed.
- The destructor of
- The output is
0 1 2
Case 2 (Not desired, but at least not 'Undefined Behavior'):
- Variable
solution
is initialized:solution_using_thread
's default constructor setsalive_
totrue
in the main thread.- The thread starts and the value of
alive_
happens to befalse
in the second thread. So thread execution ends immediately. - Before constructor returns, the second thread have already been started.
- We
throw 1
thread.join()
returns immediately because the thread has already finished.
- The output is
0 1 2
Obviously there is at least one more case in which it prints only 0
. Can you describe that case?