Reputation: 1719
class SelfTesting
{
private:
char * pChar;
SelfTesting()
{
pChar = new char[1024 * 1024 * 1024];
}
public:
static SelfTesting * pSelf;
static SelfTesting& GetInst()
{
if (!pSelf)
{
boost::lock_guard<boost::mutex> lock(g_boost_mutex);
if (!pSelf)
{
pSelf = new SelfTesting;
}
}
return *pSelf;
}
};
Generally, I know the problem is caused by:
1. allocate memory for `SelfTesting`
2. store the pointer to the allocated memory in `pChar`
3. initialize `SelfTesting`
I know that I can use local static variable to implement this pattern in C++11. My question is that is the above implementation thread safe or it is undefined when I am using C++ standard before C++11. Is boost::mutex
make sure that pSelf
will update after lock
is died?
Upvotes: 4
Views: 248
Reputation: 72044
As written, this pattern is not safe in any version of C++. In C++11 terms, you have a data race between the outer read of pSelf
and the write of pSelf
.
In general, pre-C++11, there's no such thing as guaranteed safety of multi-threaded code. The most important thing about C++11 was that it introduced into the abstract model of C++ execution the idea that there might be multiple threads of execution in the first place. Before that, there were absolutely no guarantees whatsoever about multi-threaded execution, because the concept didn't exist. Any situation where you have more than one thread is undefined as far as the standard is concerned, because it doesn't define what a thread is.
This means basically that any multi-threaded code you write in C++98 is entirely dependent on the particular implementation you use. There were some things you could rely on with mainstream compilers, though in the development of C++11, several behaviors (especially optimizations) were found in the various compilers that were not actually safe when there were multiple threads.
But this is all irrelevant, because the code as you wrote it was never guaranteed to be safe in any compiler I'm aware of. With Visual C++, you could have made it safe by making pSelf
volatile
(VC++ treated volatile
variables sort of like atomics), but that wouldn't have worked in GCC. In GCC, you would have to use the atomic intrinsics, or the Boost.Atomic library.
Upvotes: 3