简体   繁体   中英

QThread is creating a memory leak

After much testing and changes to my QT application, Visual Leak Detector identified the source of a pesky leak (8 bytes). VLD reported the QT application is clean except for a QThread* pointer.

A bit of implementation background: the application is modelled as a hybrid of solution by Jeffrey Holmes, Bulk download of web pages using Qt . Thanks to Jeffrey for the earlier solution!

Questions:

  • Why is QThread* not destroying itself when the worker thread completed its work?

  • How can I force the QThread* to delete the thread and worker object when work is complete?

  • Should QThread be implemented differently?

Code:

void vqMDIChildDialog::processWorkQueue(bool bIsBC)
{

if (m_listOfTables.isEmpty() && currentReplicationThreads == 0)
{
}
else if (!m_listOfTables.isEmpty())
{
    for (int i = 0; i < maxReplicationThreads && !m_listOfTables.isEmpty();i++)
    {
        QThread *thread = new QThread;
        QPointer<vcSharedDataQt> worker = new vcSharedDataQt();
        worker->moveToThread(thread);
        QString tmpTableName (m_listOfTables.dequeue());
        worker->setParentObject(this);
        //   
        // set properties on the worker object.
        //  
        connect(thread,  SIGNAL(started()),  worker, SLOT(process()));
        connect(worker,  SIGNAL(finished()), thread, SLOT(quit()));
        connect(worker,  SIGNAL(finished()), worker, SLOT(deleteLater()));
        connect(thread,  SIGNAL(finished()), thread,SLOT(deleteLater()));

        connect(worker,
            SIGNAL(updateMessageFromThread(  const QString&,
                             const QString&,
                             const QString&,
                             const QString&,
                             const QString&,
                             const QString&,
                             const QString&)), 

            this,
            SLOT(UpdateStatusBarFromThread( const QString&,
                            const QString&,
                            const QString&,
                            const QString&,
                            const QString&,
                            const QString&,
                            const QString&)));

        thread->setObjectName(worker->getUniqueKey());

        thread->start();
        currentReplicationThreads ++;
    }
}

}

Stack would not permit me to answer this question so:

The function was protected with a QMutex :

mutex.lock();
processWorkQueue();
mutex.unlock();

This caused the memory leak. QThread apparently could not be destroyed on worker thread completion. I removed the mutex and VLD is reporting no memory leaks with QThread .

  1. A QThread doesn't really know when its work is done. You can answer your own question by thinking of how you would implement this.

    Its run() method simply spins an event loop. Since all an event loop can know is if there are any events posted to it, the only condition you could reasonably implement is to quit the thread when there are no further events. This would make a thread quit immediately, so it's not helpful at all.

    Perhaps you'd wish to terminate the thread when there are no more QObject s that have the thread as their thread. This could certainly be implemented as an optional behavior in QThread , but whether it's a change that would get accepted I don't know. It must not be a default behavior, since in many situations constant destruction and re-creation of threads is simply wasteful - one might want to retain a thread that has no objects on it.

    Ultimately only you know when the thread's work is done. Your worker object can invoke thead()->quit() or it can emit a signal when it's done - like you do already.

  2. A QThread cannot destroy itself when the work is done, since threads are restartable. You have full control over thread's lifetime, so you certainly can destroy it when its work is done, and you do already, only you do it wrong.

  3. Your problem is really in the order that you wish for things to happen. The deleteLater operation is performed by the event loop. If a thread's event loop isn't running, the deleteLater is a NO-OP.

    So, first of all, your connections should be done such that they form a cascade that can only execute in a well-defined order:

     connect(thread, SIGNAL(started()), worker, SLOT(process())); connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); connect(worker, SIGNAL(destroyed()), thread, SLOT(quit())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 

    Then, you must ensure that the thread where your processWorkQueue method runs is not blocked and has a chance for its event loop to proceed. It's this event loop that will process thread's deletion.

    As noted by AlexP, this doesn't work in Qt 4.7 or earlier, since all those versions had a bug in QThread's implementation. "QThread's behavior has changed" is an euphemism for "there was an ugly bug that finally fixed".

  4. Your connect is overly verbose. You can drop spaces and reference/const-reference from the signature. The third argument is also optional if it's this . It should look like:

     connect(worker, SIGNAL(updateMessageFromThread(QString,QString,QString,QString, QString,QString,QString)), SLOT(updateStatusBarFromThread(QString,QString,QString,QString, QString,QString,QString))); 

Answers:

  • Why is QThread* not destroying itself when the worker thread completed its work?

Because there are different ways to use QThread in which at least one must be able to query thread states or class members after worker has finished. Also the thread may be restarted.

  • How can I force the QThread* to delete the thread and worker object when work is complete?

The finished signal should be enough for you to call a slot deleting both.

  • Should QThread be implemented differently?

There are different implementations for different situations. http://qt-project.org/doc/qt-5.0/qtcore/thread-basics.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM