The Singleton Pattern
-
I'm think that I'm tracking with you. If the mutex is made a member variable of the object then this won't happen, yes?
-
-
For the double-checked locking pattern to be thread-safe, in addition to using a mutex, the read and write to m_MathUtility must be atomic. [1]
@
class MathUtility
{
static QAtomicPointer<MathUtility> m_MathUtility;
static QMutex mutex;
public:
static MathUtility* Mathematics();
static void Drop();
};
@@
QAtomicPointer<MathUtility> MathUtility::m_MathUtility;
QMutex MathUtility::mutex;MathUtility* MathUtility::Mathematics()
{
if( !m_MathUtility )
{
mutex.lock();
if( !m_MathUtility )
m_MathUtility = new MathUtility;
mutex.unlock();
}
return m_MathUtility;
}void MathUtility::Drop()
{
mutex.lock();
delete m_MathUtility;
m_MathUtility = 0;
mutex.unlock();
}
@[1] http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
-
Very interesting reading on the concept (and perils) of the singleton pattern! Thanks for all of the suggestions and advice. Until today, I had never heard about something called QAtomicPointer.
-
Local statics to implement singletons are cool, but I hate the fact that modern compilers throw in implicit (dead-)locking code. So I tend to disable that and use "my own local static allocator":https://github.com/unclefrank/libftl/blob/master/ftl/LocalStatic.hpp instead. Just my two cents.
-
Also, it is worth while to use QMutexLocker when dealing with mutexes. This saves having to catch exceptions all over the place and ensuring that your mutex is properly unlocked. The QMutexLocker destructor does this for you even if an exception is thrown as the stack is unwound.
-
See "C++ FAQ 16.8":http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.8:
bq. C++ language guarantees that delete p will do nothing if p is equal to NULL. Since you might get the test backwards, and since most testing methodologies force you to explicitly test every branch point, you should not put in the redundant if test.
It is guaranteed by the standard that assigning 0 (digit zero) to a pointer in the source code is equivalent to assigning null to the pointer (the same holds for comparison with ==).
This is independent of the internal representation of a null pointer! The latter can be different from the numeric value zero, so memsetting all bits of a pointer to zero can lead to something different than a null pointer!