Unsolved Singleton Example
-
In writing this small example, I have seen many posts about making a singleton "thread safe". What does this mean? Please, critique the example and make corrections and suggestions to make it better and "thread safe".
globals.h :
#ifndef GLOBALS_H #define GLOBALS_H #include <QMainWindow> #include <QPushButton> #include <QDebug> #endif // GLOBALS_H
main.cpp :
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.setFixedSize(QSize(300, 200)); w.show(); return a.exec(); }
mainwindow.h :
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include "globals.h" #ifndef SINGLETONTEST_H #include "singletontest.h" #endif #ifndef CLASSAAAA_H #include "classaaaa.h" #endif class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); QPushButton* testButton; SingletonTest* sData; ClassAAAA* aaaa; public slots: void SLOT_MainWindow(int); signals: void SIGNAL_MainWindow(int); }; #endif // MAINWINDOW_H
mainwindow.cpp :
#include "mainwindow.h" //---------- CONSTRUCTOR MainWindow ---------- MainWindow :: MainWindow(QWidget *parent) : QMainWindow(parent) { qDebug()<<"CONSTRUCTOR MainWindow"; testButton = new QPushButton("Test", this); testButton->setGeometry(50, 50, 60, 24); sData = SingletonTest::getInstance(); aaaa = new ClassAAAA(this); connect(testButton, &QPushButton::clicked, sData, &SingletonTest::SLOT_SingletonTest); connect(sData, &SingletonTest::SIGNAL_SingletonTest, this, &MainWindow::SLOT_MainWindow); connect(this, &MainWindow::SIGNAL_MainWindow, aaaa, &ClassAAAA::SLOT_aaaa); } //---------- DESTRUCTOR MainWindow ---------- MainWindow :: ~MainWindow() { qDebug()<<"DESTRUCTOR ~MainWindow"; delete sData; } //---------- SLOT_MainWindow ---------- void MainWindow :: SLOT_MainWindow(int num){ qDebug()<<"MainWindow :: SLOT_MainWindow num: "<<num; emit SIGNAL_MainWindow(num); }
classaaaa.h :
#ifndef CLASSAAAA_H #define CLASSAAAA_H #ifndef GLOBALS_H #include "globals.h" #endif #ifndef SINGLETONTEST_H #include "singletontest.h" #endif class ClassAAAA : public QWidget { Q_OBJECT private: SingletonTest* asData; public: explicit ClassAAAA(QWidget *parent); ~ClassAAAA(); public slots: void SLOT_aaaa(int); signals: void SIGNAL_messageFromAAAA(int); }; #endif // CLASSAAAA_H
classaaaa.cpp :
#include "classaaaa.h" //---------- CONSTRUCTOR ClassAAAA ---------- ClassAAAA :: ClassAAAA(QWidget *parent) : QWidget(parent){ qDebug()<<"CONSTRUCTOR ClassAAAA"; asData = SingletonTest::getInstance(); connect(this, &ClassAAAA::SIGNAL_messageFromAAAA, asData, &SingletonTest::SLOT_SingletonTestHandleMessage); } //---------- DESTRUCTOR ClassAAAA ---------- ClassAAAA :: ~ClassAAAA(){ qDebug()<<"DESTRUCTOR ~ClassAAAA"; } //---------- SLOT_aaaa ---------- void ClassAAAA :: SLOT_aaaa(int anumber){ qDebug()<<"ClassAAAA :: SLOT_aaaa anumber: "<<anumber; emit SIGNAL_messageFromAAAA(8888); }
singletontest.h :
#ifndef SINGLETONTEST_H #define SINGLETONTEST_H #ifndef GLOBALS_H #include "globals.h" #endif class SingletonTest : public QObject { Q_OBJECT friend class MainWindow; private: SingletonTest(); static SingletonTest* instance; public: static SingletonTest* getInstance(); ~SingletonTest(); public slots: void SLOT_SingletonTest(); void SLOT_SingletonTestHandleMessage(int); signals: void SIGNAL_SingletonTest(int); }; #endif // SINGLETONTEST_H
singletontest.cpp :
#include "singletontest.h" //---------- instance = 0 ---------- SingletonTest* SingletonTest :: instance = 0; //---------- CONSTRUCTOR SingletonTest ---------- SingletonTest :: SingletonTest(){ qDebug()<<"CONSTRUCTOR SingletonTest"; } //---------- DESTRUCTOR SingletonTest ---------- SingletonTest :: ~SingletonTest(){ qDebug()<<"DESTRUCTOR ~SingletonTest"; } //---------- getInstance ---------- SingletonTest* SingletonTest :: getInstance(){ if (instance == 0) { instance = new SingletonTest(); }//if return instance; } //---------- SLOT_SingletonTest ---------- void SingletonTest :: SLOT_SingletonTest(){ qDebug()<<"SingletonTest :: SLOT_SingletonTest"; emit SIGNAL_SingletonTest(7777); } //---------- SLOT_SingletonTestHandleMessage ---------- void SingletonTest :: SLOT_SingletonTestHandleMessage(int m){ qDebug()<<"SingletonTest :: SLOT_SingletonTestHandleMessage m: "<<m; }
-
How is this supposed to be thread safe?
Just a basic example, wheninstance
is null, callinggetInstance()
from 2 different threads is a race condition -
@kendavistoo said in Singleton Example:
SingletonTest* SingletonTest :: getInstance(){
if (instance == 0) { instance = new SingletonTest(); }//if return instance;
}
Thanks, VRonin. Is there anyway to fix this?
-
Hi,
You have to use proper threading synchronisation tools to avoid resources being accessed from several thread at the same time.
However, the first question is rather: do you really need a singleton for what you want to achieve ?
-
@SGaist said in Singleton Example:
do you really need a singleton for what you want to achieve ?
No?! I have not seen even one case where a singleton (as described in the infamous Gang of Four's book) is needed, ever!