Is this thread safe:
class X;
class Once {
public:
Once(X* x) : x_(x) {}
X* Get() {
if (!x_) return NULL;
// all dirty reads end up here.
// This could be any type of scoped lock...
some_scoped_lock lock(m);
// if (!x_) return x_; // omitted because it's a no op
X* ret(x_); // might get NULL if we waited for lock
x_ = NULL; // idempotent
return ret;
}
private:
X *x_;
some_kind_of_mutex m;
// Boilerplate to make all other constructors and default function private
....
}
(edit: i'm interested in both c++11 and older versions)
As I understand it the problem with Double-checked locking is that in some memory models the write to the guarded var can occur and become visible to early. I think the above code doesn't have this issue because there is no precondition for the validity of the new value. I think the only requirement for this to be correct code is that all reads under the lock must be clean with respect to writes in the constructor and writes under the lock.
Update: OK, it seems that this invokes the "undefined behavior" pitfall and therefor can legally do anything, including drain your bank account. That said, are there any cases where it will misbehave?