Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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, when instance is null, calling getInstance() 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?


  • Lifetime Qt Champion

    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 ?


  • Qt Champions 2017

    @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!


Log in to reply