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

Application crashes on QThread::quit()



  • Hey Gurus!

    I have a QObject class which I launch in a QThread. Everything seems to be working fine until I try to QThread::quit() the thread, at which point my application crashes with an:
    ASSERT failure in QMutexLocker: "QMutex pointer is misaligned", file thread\qmutex.h, line 196
    Whilst I have been developing code in Visual Studio for many years, I'm quite new to QT (which I'm loving BTW!). To be honest, I'm not sure how to quit the thread and close my QObject class correctly. My code is as follows:

    Header of my QObject Class:

    #ifndef UPNPDISCOVERTHREAD_H
    #define UPNPDISCOVERTHREAD_H
    
    #include "../upnp/avcontrol.hpp"
    #include "../upnp/actioninfo.hpp"
    
    #include <QObject>
    #include <QThread>
    #include <QDebug>
    
    namespace upnp
    {
     class CControlPoint;
    };
    
    USING_UPNP_NAMESPACE
    
    class CUpnpDiscoverThread : public QObject
    {
        Q_OBJECT
    public:
        explicit CUpnpDiscoverThread(int numSwitches, QObject *parent = nullptr);
        ~CUpnpDiscoverThread();
        void start(QThread &thread);
    
    signals:
        /*! Emitted when a all switches are found. */
        void scanComplete(QVarLengthArray<struct WemoSwitch *> *ws);
    
    protected slots:
        void newDevice (QString const & uuid);
        void upnpError (int errorCode, QString const & errorString);
        void networkError (QString const & deviceUUID, QNetworkReply::NetworkError errorCode, QString const & errorString);
        void isScanFinished();
    
    public slots:
        void startDiscovery();
        void quit();
    
    private:
        CControlPoint* m_cp = nullptr; //!< It is the CControlPoint.
        QList<CControlPoint::TArgValue> m_args;
        int GetSignalStrength( struct WemoSwitch *ws );
        int m_switchCount; // Because I don't know when the network scan is complete, I count the number of switches discovered every X secs, if it hasn't changed in Y secs, then I assume the scan is complete
        int m_retrySwitchCount; // The number of times to retry the switch count before timing out.
        int m_numSwitches; // The number of scanned switches expected to be found
        QVarLengthArray<struct WemoSwitch *> m_wemoSwitches;
    };
    
    #endif // UPNPDISCOVERTHREAD_H
    

    QObject CPP (part of):

    #include "upnpdiscoverthread.h"
    #include "globals.h"
    
    #include <QDir>
    #include <QSettings>
    #include <QtXml>
    #include <QMessageBox>
    #include <QDebug>
    
    CUpnpDiscoverThread::CUpnpDiscoverThread(int numSwitches, QObject *parent) : m_numSwitches( numSwitches), QObject(parent)
    {
    }
    
    CUpnpDiscoverThread::~CUpnpDiscoverThread()
    {
        if ( m_cp )
        {
            m_cp->close();
    
            delete m_cp;
        }
    }
    
    void CUpnpDiscoverThread::start(QThread &thread)
    {
        connect( &thread, SIGNAL(started()), this, SLOT(startDiscovery()));
        connect( &thread, SIGNAL(finished()), this, SLOT(quit()));
    }
    
    void CUpnpDiscoverThread::startDiscovery()
    {
        qDebug() << "Starting discovery";
    
       ...
    }
    
    void CUpnpDiscoverThread::quit()
    {
        quit();
    }
    
    void CUpnpDiscoverThread::isScanFinished()
    {
          emit scanComplete( &m_wemoSwitches);
    }
    

    Main window construction and execution of thread:

    CUpnpDiscoverThread *m_discover = new CUpnpDiscoverThread( count );
    
    QThread *m_discoverThread = new QThread( this );
    
    m_discover->start( *m_discoverThread );
    
    m_discover->moveToThread( m_discoverThread );
    
    m_discoverThread->start();
    
    connect( m_discover, &CUpnpDiscoverThread::scanComplete, this, &MainWindow::scanComplete );
    

    Main window termination of thread (called in the scanComplete SLOT):

    m_discoverThread->quit();
    
    delete m_discoverThread;
    
    delete m_discover;
    
    • Could someone please shed some light on what I am doing wrong, and how to correctly terminate my thread and class?

    • I assumed that the QThread::quit() would send a finished SIGNAL to my QObject?

    • I assume it is up to me to delete the QThread and QObject?

    Thanks heaps in advance.

    Steve Q. :-)


  • Moderators

    @steveq said in Application crashes on QThread::quit():

    void CUpnpDiscoverThread::quit()
    {
    quit();
    }

    That's an infinite loop :-)

    m_discover->start( *m_discoverThread );
    m_discover->moveToThread( m_discoverThread );

    You should connect the signals and slots after moving the object to thread.

    m_discoverThread->quit();

    You should also call m_discoverThread->wait();

    delete m_discover;

    A nicer way is to connect thread's finished() signal to m_discover's deleteLater() slot.

    Hope these hints help. I have not analysed the whole code.



  • Hi Sierdzio,

    With regards to the infinite loop. What can I say... oops! Lol

    I have tried your suggested changes (and fixed the infinite loop!), but the code never arrives at my break points.

    My app crashes on the m_discoverThread->quit(); line!

    I'm at a bit of a loss as to what to do.

    Thanks,

    SQ


  • Moderators

    @steveq said in Application crashes on QThread::quit():

    QThread *m_discoverThread = new QThread( this );

    hmmmm... you are creating a local variable here, right? If yes, then what you call quit() on?

    I think your m_discoverThread (class member) is still a nullptr! So you should change that to:

    m_discoverThread = new QThread( this );
    


  • OMG I can't believe I didn't see this!!

    What a silly mistake.

    Thanks so much Sierdzio, I feel like a goose!

    I guess sometimes you look too hard, and it takes a second pair of eyes.

    I'll fix this soon and let you know.

    Thanks heaps once again,

    -SQ :-)


  • Moderators

    @steveq said in Application crashes on QThread::quit():

    Thanks so much Sierdzio, I feel like a goose!

    heh, no need to feel bad. I guess every programmer could share a story where they missed a single semicolon and kept debugging for 2 days :D That just happens sometimes.



  • Thanks again Sierdzio, as expected, this has fixed it!

    -SQ :-)


Log in to reply