静态方法GetUI是用鼠标事件调用的,但从调试中注意到,在极少数情况下,构造函数会用鼠标事件的冲击调用两次。
问题是调度程序在构建过程中停止,切换到另一个任务进程调用,该调用也开始创建另一个实例?
Object* Interface::instance = 0;
Object* Interface::GetUI() {
if (instance == 0) {
instance = new Interface();
}
return instance;
}
您实际上应该锁定singleton,否则,在多线程时,您将创建多个实例
对于C++11,您可以按如下方式使用它。
#include <mutex>
class Singleton
{
static Singleton *singletonInstance;
Singleton() {}
static std::mutex m_;
public:
static Singleton* getSingletonInstance()
{
std::lock_guard<std::mutex> lock(m_);
if(singletonInstance == nullptr)
{
singletonInstance = new Singleton();
}
return singletonInstance;
}
}
您所描述的行为只能在从多个线程使用GetUI
时出现。我希望您知道,如果没有适当的锁定或使用排队的方法调用,就无法对GUI方法进行任何直接调用。
下面显示了在Qt中创建全局变量的线程安全、惯用的方法。真的没有理由再实施一次。有时NIH很糟糕。
#include <QtGlobal>
class Object {};
class Interface {
public:
static Object * GetUI();
};
// This must be in a *single* source file *only*. Not in header!
Q_GLOBAL_STATIC(Object, interfaceInstance)
Object* Interface::GetUI() {
return interfaceInstance;
}
问题在于对象的创建和实例化。有两个可能的解决方案;可以同步CCD_ 2功能,正如Jerry YY所建议的,或者您可以确保singleton在开始线程处理之前创建;只出现竞争条件当您在至少一个线程中修改对象时您已经创建了对象,instance
永远不会被修改。
一种方法是简单地定义Interface::instance
作为:
Object* Interface::instance = Interface::GetUI();
零初始化确保Interface::GetUI
调用,Interface::instance
初始化为null指针,并且进行静态对象的初始化在CCD_ 7之前。
否则:如果你确信Interface::GetUI
永远不会在进入main
之前调用(考虑到你说过;在你之前不应该有任何鼠标事件输入main
(,然后可以放弃测试(或将其替换为assert( instance != nullptr
(在Interface::GetUI
中写入:
Object* Interface::instance = new Interface();
简单多了,避免了所有的问题。
这里有一个更好的带有模板的单例实现:
template <class T>
class Singleton
{
private:
static T * _instance;
protected:
Singleton (){}
public:
static T & get()
{
if (_instance)
{
return *_instance;
}
_instance = new T();
return *_instance;
}
};
template <class T> T* Singleton<T>::_instance = 0;
现在用继承实现它:
class Foo : public Singleton<Foo>
并在任何地方使用:
Foo::get().DoSomething();
这是早期解决方案的更快版本(减少了互斥体开销的使用(。
#include <mutex>
class Singleton
{
static volatile Singleton * singletonInstance;
Singleton() {}
static std::mutex m_;
public:
static Singleton* getSingletonInstance()
{
if(singletonInstance == nullptr)
{
std::lock_guard<std::mutex> lock(m_);
if(singletonInstance == nullptr) {
Singleton *tmp = new Singleton(); // fight with compiler see link in comment
singletonInstance = tmp;
}
}
return singletonInstance;
}
}
无论如何,我不相信多线程是一个问题,因为您已经写过鼠标事件,这应该只来自主线程。添加断言Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread())
以确保这是同步的问题(如果它失败,请检查调用堆栈(。
我还建议禁用赋值运算符和复制构造函数。
您的实例和GetUI((方法必须是静态的。