Qt Singleton实施 [英] Qt Singleton implementation

查看:101
本文介绍了Qt Singleton实施的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找Singleton Qt实现,并发现了.但我对此有疑问.

I was looking for a Singleton Qt implementation and found this. but I have some question about it.

  1. create设为QBasicAtomicPointer的目的是什么?
  2. 如果以前使用过fetchAndStoreAcquire,在qCallOnce中使用testAndSetRelaxed有什么意义?习得语义不是已经在阻止它之后的任何内存重新排序了吗?
  3. qCallOncePerThread功能的作用是什么? qCallOnce已经不是线程安全的吗?
  1. What is the purpose of making create a QBasicAtomicPointer ?
  2. What is the point in qCallOnce of using testAndSetRelaxed if previously we have used fetchAndStoreAcquire ? Isn't the acquire semantic already preventing any memory reordering after it ?
  3. What is the purpose of the qCallOncePerThread function ? Isn't qCallOnce already thread-safe ?

我在此处复制建议的实施内容:

I copy the contents of the suggested implementation here:

call_once.h

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

singleton.h

singleton.h

#ifndef SINGLETON_H
#define SINGLETON_H

#include <QtGlobal>
#include <QScopedPointer>
#include "call_once.h"

template <class T>
class Singleton
{
private:
  typedef T* (*CreateInstanceFunction)();
public:
  static T* instance(CreateInstanceFunction create);
private:
  static void init();

  Singleton();
  ~Singleton();
  Q_DISABLE_COPY(Singleton)
  static QBasicAtomicPointer<void> create;
  static QBasicAtomicInt flag;
  static QBasicAtomicPointer<void> tptr;
  bool inited;
};

template <class T>
T* Singleton<T>::instance(CreateInstanceFunction create)
{
  Singleton::create.store(create);
  qCallOnce(init, flag);
  return (T*)tptr.load();
}

template <class T>
void Singleton<T>::init()
{
  static Singleton singleton;
  if (singleton.inited) {
    CreateInstanceFunction createFunction = (CreateInstanceFunction)Singleton::create.load();
    tptr.store(createFunction());
  }
}

template <class T>
Singleton<T>::Singleton() {
  inited = true;
};

template <class T>
Singleton<T>::~Singleton() {
  T* createdTptr = (T*)tptr.fetchAndStoreOrdered(nullptr);
  if (createdTptr) {
    delete createdTptr;
  }
  create.store(nullptr);
}

template<class T> QBasicAtomicPointer<void> Singleton<T>::create = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
template<class T> QBasicAtomicInt Singleton<T>::flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);
template<class T> QBasicAtomicPointer<void> Singleton<T>::tptr = Q_BASIC_ATOMIC_INITIALIZER(nullptr);

#endif // SINGLETON_H

使用方法

// myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>

class MyClass : public QObject
{
    Q_OBJECT

private:
    MyClass(QObject* parent = 0);
    static MyClass* createInstance();
public:
    ~MyClass();
    static MyClass* instance();
};

#endif // MYCLASS_H


// myclass.cpp

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include "singleton.h"

MyClass::MyClass(QObject* parent):
 QObject(parent)
{
}

MyClass* MyClass::createInstance()
{
    return new MyClass();
}

MyClass::~MyClass()
{
}

MyClass* MyClass::instance()
{
    return Singleton<MyClass>::instance(MyClass::createInstance);
}

#endif // MYCLASS_H

main.cpp

#include <QTextStream>
#include "myclass.h"

#define MyClassInstance Singleton<MyClass>::instance()

int main(int argc, char* argv[])
{
    QTextStream(stdout) << MyClass::instance()->metaObject()->className() << endl;
    return 0;
}

推荐答案

我认为使用下一个单例实现就足够了.我记得,C ++ 11保证静态变量只有一个实例化/初始化. 最初的问题是,如果有多个线程尝试同时访问一个实例,并且有可能会发生两次创建单例的情况.

I think that is will be enough to use next singleton implementation. As I remember, C++11 gurantees that there will be only one instancing/initialization for a static variable. Original problem was in case, when more than one thread tries to access an instance in same time and there were possible a situation, when singleton was created twice.

template <typename T, typename D = T>
class Singleton
{
    friend D;
    static_assert(std::is_base_of_v<T, D>, "T should be a base type for D");

public:
    static T& instance();

private:
    Singleton() = default;
    ~Singleton() = default;
    Singleton( const Singleton& ) = delete;
    Singleton& operator=( const Singleton& ) = delete;
};

template <typename T, typename D>
T& Singleton<T, D>::instance()
{
    static D inst;
    return inst;
}

// Usage:
class MyClass : public Singleton<MyClass>
{
public:
    void foo(){}
};

// Access: 
MyClass::instance().foo();

这篇关于Qt Singleton实施的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆