使用鼠标事件调用静态方法GetUI,但是在调试中注意到,在一些非常罕见的情况下,鼠标事件发生时,构造函数被调用两次。
问题是调度程序在构造过程中停止,切换到另一个也开始创建另一个实例的任务进程调用?
Object* Interface::instance = 0;
Object* Interface::GetUI() {
if (instance == 0) {
instance = new Interface();
}
return instance;
}
答案 0 :(得分:4)
实际上你应该锁定单例,否则,当多线程时,你将创建多个实例 对于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;
}
}
答案 1 :(得分:1)
问题是你之间有竞争条件
创建和对象的实例化。那里有两个
可能的解决方案;你可以同步GetUI
函数,
正如Jerry YY建议的那样,或者你可以确保单身人士
在开始线程之前创建;只有竞争条件才会发生
当您在至少一个线程中修改对象时,一次
您已创建对象,instance
永远不会被修改。
这样做的一种方法是简单地定义Interface::instance
as:
Object* Interface::instance = Interface::GetUI();
零初始化确保在Interface::GetUI
之前
调用Interface::instance
初始化为null
指针,以及静态对象的初始化发生
在main
之前。
否则:如果您确定Interface::GetUI
永远不会
在进入main
之前调用(看起来很可能,给出了什么
你已经说过了 - 你之前不应该有任何鼠标事件
输入main
),然后您可以放弃测试(或替换为
assert( instance != nullptr
中的Interface::GetUI
)
写:
Object* Interface::instance = new Interface();
更简单,并避免所有问题。
答案 2 :(得分:1)
您描述的行为只能在多个线程使用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;
}
答案 3 :(得分:0)
这是一个带有模板的更好的单例实现:
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();
答案 4 :(得分:-1)
以下是earlier solution的更快版本(减少了互斥开销的使用)。
#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())
以确保这是同步问题(如果检查调用堆栈失败)。
我建议也禁用assign operator和copy constructor。
答案 5 :(得分:-3)
您的实例和GetUI()方法必须是静态的。