Say I define a toy class that I want to claim is thread-safe.
(Added following long discussion in comments: This a thought experiment about a race that I believe is commonly present and largely benign, but nevertheless real. It is between the initialization of a data member in a constructor, and its otherwise correct use in another thread that did not synchronize with the constructor. I am looking for a direct solution to the problem that would likely need to be in the constructor. It is easy to work-around and avoid this problem in practice.)
class Blah {
public:
Blah () { m_blah = 123; }
int blah () {
std::lock_guard _{m_mutex};
m_blah += 1;
return m_blah;
}
private:
std::mutex m_mutex;
int m_blah;
};
Now there is nothing to stop someone else doing the following ...
std::atomic<Blah *> ptr{nullptr};
ptr.store (new Blah(), std::memory_order_relaxed)
..., and accessing a freshly-made Blah from another thread that is already running (i.e. there is no synchronization as the second thread starts).
if (auto p = ptr.load()) p->blah();
They see a race between the initialization of m_blah
and the critical section protected by the mutex. They blame me because I said the class was thread-safe, and it broke when used in at least a technically legal way.
Should I
not worry about it because the user had it coming (and everyone else would also call the class thread-safe)
take the mutex in the constructor to synchronize the memory (and hope that works, which it might not because the state of the mutex might not be synchronized), or
synchronize the memory inside the class in some other way?
Assuming I wanted to go with 3) even though that would presumably be unusual, what would be the best way?