For create thread-safe singleton we must first write our call_once() implementation:
// call_once.h
#ifndef CALL_ONCE_H#define CALL_ONCE_H #include <QtGlobal>#include <QAtomicInt>#include <QMutex>#include <QWaitCondition>#include <QThreadStorage>#include <QThread> namespace CallOnce {
enum ECallOnce {
CO_Request,
CO_InProgress,
CO_Finished };
Q_GLOBAL_STATIC(QThreadStorage<QAtomicInt*>, once_flag)} template <class Function>inline static void qCallOnce(Function func, QBasicAtomicInt& flag){
using namespace CallOnce; #if QT_VERSION < 0x050000
int protectFlag = flag.fetchAndStoreAcquire(flag);#elif QT_VERSION >= 0x050000
int protectFlag = flag.fetchAndStoreAcquire(flag.load());#endif if (protectFlag = CO_Finished)
return;
if (protectFlag = CO_Request && flag.testAndSetRelaxed(protectFlag,
CO_InProgress)) {
func();
flag.fetchAndStoreRelease(CO_Finished);
}
else {
do {
QThread::yieldCurrentThread();
}
while (!flag.testAndSetAcquire(CO_Finished, CO_Finished));
}} template <class Function>inline static void qCallOncePerThread(Function func){
using namespace CallOnce;
if (!once_flag()->hasLocalData()) {
once_flag()->setLocalData(new QAtomicInt(CO_Request));
qCallOnce(func, *once_flag()->localData());
}} #endif // CALL_ONCE_H
It our singleton template
// singleton.h
#ifndef SINGLETON_H#define SINGLETON_H #include <QtGlobal>#include <QScopedPointer>#include "call_once.h" template <class T>class Singleton{public:
static T& instance()
{
qCallOnce(init, flag);
return *tptr;
} static void init()
{
tptr.reset(new T);
} private:
Singleton() {};
~Singleton() {};
Q_DISABLE_COPY(Singleton) static QScopedPointer<T> tptr;
static QBasicAtomicInt flag;}; template<class T> QScopedPointer<T> Singleton<T>::tptr(0);template<class T> QBasicAtomicInt Singleton<T>::flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request); #endif // SINGLETON_H
How to use
// myclass.h
#ifndef MYCLASS_H#define MYCLASS_H #include <QObject> class MyClass : public QObject{
Q_OBJECT public:
MyClass(QObject* parent = 0);}; #endif // MYCLASS_H
// main.cpp
#include "singleton.h"#include "myclass.h" #define MyClassInstance Singleton<MyClass>::instance() int main(int argc, char* argv[]){
QTextStream(stdout) << MyClassInstance.metaObject()->className() << endl;
return 0;}