QThread is creating a memory leak

前端 未结 2 1041
我寻月下人不归
我寻月下人不归 2021-01-27 07:36

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

相关标签:
2条回答
  • 2021-01-27 08:05
    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 QObjects 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)));
      
    0 讨论(0)
  • 2021-01-27 08:18

    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

    0 讨论(0)
提交回复
热议问题