Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QThread creation and cleanup
QtWS25 Last Chance

QThread creation and cleanup

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 4 Posters 5.8k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Amomum
    wrote on last edited by
    #1

    I know that questions like this one were already asked multiple times but I still can't find an exact answer.
    I have a Worker class derived from QObject. I create ans instance of QThread, move worker into new thread, connect some signals. In the worker init method I create a timer and I do some work periodically. This work should be done all the time, until the app is closed. To kill the thread I call quit in window's destructor and wait for it to quit.

    My concern is that worker's desctuctor is never called. I know that I should not allocate any resources in the worker constructor (coz they will be allocated in the different thread), I do all my allocatoins in the init method and all my deallocations in worker's deleteLater slot (which I connected to threads quit signal). But I'm not sure if it's safe to just omit destructors call entirely, may be QObject needs to do something important?

    Please tell me how should I do it right?

    Here's the code:

    auto worker = new Worker();
    
    worker->moveToThread( &m_workerThread );
    
    connect( worker, &Worker::finished, &m_workerThread, &QThread::quit );
    connect( worker, &Worker::finished, worker, &Worker::deleteLater );
        
    connect( &m_workerThread, &QThread::finished, &m_workerThread, &QThread::deleteLater );
    connect( &m_workerThread, &QThread::finished, worker, &Worker::deleteLater );
    connect( &m_workerThread, &QThread::started,  worker, &Worker::init );
    
    m_workerThread.start();
    
    
    
    MainWindow::~MainWindow()
    {
        qDebug() << "Window deleted";
    
        m_workerThread.quit();
        m_workerThread.wait();
    
        delete m_ui;
    }
    

    I'm also a puzzled about how should I create worker and qthread? Should they be heap allocated? Or can I make them simple member variables? I can't set a parent to a worker class, since it gets moved to thread, but should a qthread have a parent?

    raven-worxR kshegunovK J.HilkJ 3 Replies Last reply
    0
    • A Amomum

      I know that questions like this one were already asked multiple times but I still can't find an exact answer.
      I have a Worker class derived from QObject. I create ans instance of QThread, move worker into new thread, connect some signals. In the worker init method I create a timer and I do some work periodically. This work should be done all the time, until the app is closed. To kill the thread I call quit in window's destructor and wait for it to quit.

      My concern is that worker's desctuctor is never called. I know that I should not allocate any resources in the worker constructor (coz they will be allocated in the different thread), I do all my allocatoins in the init method and all my deallocations in worker's deleteLater slot (which I connected to threads quit signal). But I'm not sure if it's safe to just omit destructors call entirely, may be QObject needs to do something important?

      Please tell me how should I do it right?

      Here's the code:

      auto worker = new Worker();
      
      worker->moveToThread( &m_workerThread );
      
      connect( worker, &Worker::finished, &m_workerThread, &QThread::quit );
      connect( worker, &Worker::finished, worker, &Worker::deleteLater );
          
      connect( &m_workerThread, &QThread::finished, &m_workerThread, &QThread::deleteLater );
      connect( &m_workerThread, &QThread::finished, worker, &Worker::deleteLater );
      connect( &m_workerThread, &QThread::started,  worker, &Worker::init );
      
      m_workerThread.start();
      
      
      
      MainWindow::~MainWindow()
      {
          qDebug() << "Window deleted";
      
          m_workerThread.quit();
          m_workerThread.wait();
      
          delete m_ui;
      }
      

      I'm also a puzzled about how should I create worker and qthread? Should they be heap allocated? Or can I make them simple member variables? I can't set a parent to a worker class, since it gets moved to thread, but should a qthread have a parent?

      raven-worxR Offline
      raven-worxR Offline
      raven-worx
      Moderators
      wrote on last edited by
      #2

      @Amomum
      QThread::quit() only quits it's event-loop -> means when you used QThread::exec() in the run() method.
      QThread::wait() just waits, nothing more.

      So how does your run() implementation look like? You need to make sure that the thread finishes (returns from run()) at some point, since you already connected it's finished signal to deleteLater().

      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
      If you have a question please use the forum so others can benefit from the solution in the future

      A 1 Reply Last reply
      0
      • A Amomum

        I know that questions like this one were already asked multiple times but I still can't find an exact answer.
        I have a Worker class derived from QObject. I create ans instance of QThread, move worker into new thread, connect some signals. In the worker init method I create a timer and I do some work periodically. This work should be done all the time, until the app is closed. To kill the thread I call quit in window's destructor and wait for it to quit.

        My concern is that worker's desctuctor is never called. I know that I should not allocate any resources in the worker constructor (coz they will be allocated in the different thread), I do all my allocatoins in the init method and all my deallocations in worker's deleteLater slot (which I connected to threads quit signal). But I'm not sure if it's safe to just omit destructors call entirely, may be QObject needs to do something important?

        Please tell me how should I do it right?

        Here's the code:

        auto worker = new Worker();
        
        worker->moveToThread( &m_workerThread );
        
        connect( worker, &Worker::finished, &m_workerThread, &QThread::quit );
        connect( worker, &Worker::finished, worker, &Worker::deleteLater );
            
        connect( &m_workerThread, &QThread::finished, &m_workerThread, &QThread::deleteLater );
        connect( &m_workerThread, &QThread::finished, worker, &Worker::deleteLater );
        connect( &m_workerThread, &QThread::started,  worker, &Worker::init );
        
        m_workerThread.start();
        
        
        
        MainWindow::~MainWindow()
        {
            qDebug() << "Window deleted";
        
            m_workerThread.quit();
            m_workerThread.wait();
        
            delete m_ui;
        }
        

        I'm also a puzzled about how should I create worker and qthread? Should they be heap allocated? Or can I make them simple member variables? I can't set a parent to a worker class, since it gets moved to thread, but should a qthread have a parent?

        kshegunovK Offline
        kshegunovK Offline
        kshegunov
        Moderators
        wrote on last edited by kshegunov
        #3

        @Amomum said in QThread creation and cleanup:

        My concern is that worker's desctuctor is never called.

        It should be, when you return control to the thread's event loop (or after the finished() signal). How do you test it exactly?

        I know that I should not allocate any resources in the worker constructor (coz they will be allocated in the different thread)

        Well, this is wrong. You can allocate whatever you want in the constructor, but you should set the correct parent to your QObject instances, so they get moved with it to the correct thread.

        I do all my allocatoins in the init method

        This is also fine.

        all my deallocations in worker's deleteLater slot (which I connected to threads quit signal)

        This is suspicious. deleteLater isn't virtual so you probably have overloaded the QObject's slot and thus you don't get your object deleted. Please show a snippet for this piece of your code.

        But I'm not sure if it's safe to just omit destructors call entirely

        No. It may be safe, but you should take care to clean up your stuff in any case.

        What you posted looks perfectly okay.
        Note that connect( worker, &Worker::finished, worker, &Worker::deleteLater ); is superfluous, however.

        I'm also a puzzled about how should I create worker and qthread? Should they be heap allocated?

        Not necessarily, but heap allocation will work okay the way you've done it.

        but should a qthread have a parent

        Unless you intend to delete it manually (which you do with deleteLater), yes, you should set a parent to it. However, since you create the thread with auto-storage (on the stack) you shouldn't delete it to begin with, the stack will take care to free the memory.

        Read and abide by the Qt Code of Conduct

        1 Reply Last reply
        1
        • A Amomum

          I know that questions like this one were already asked multiple times but I still can't find an exact answer.
          I have a Worker class derived from QObject. I create ans instance of QThread, move worker into new thread, connect some signals. In the worker init method I create a timer and I do some work periodically. This work should be done all the time, until the app is closed. To kill the thread I call quit in window's destructor and wait for it to quit.

          My concern is that worker's desctuctor is never called. I know that I should not allocate any resources in the worker constructor (coz they will be allocated in the different thread), I do all my allocatoins in the init method and all my deallocations in worker's deleteLater slot (which I connected to threads quit signal). But I'm not sure if it's safe to just omit destructors call entirely, may be QObject needs to do something important?

          Please tell me how should I do it right?

          Here's the code:

          auto worker = new Worker();
          
          worker->moveToThread( &m_workerThread );
          
          connect( worker, &Worker::finished, &m_workerThread, &QThread::quit );
          connect( worker, &Worker::finished, worker, &Worker::deleteLater );
              
          connect( &m_workerThread, &QThread::finished, &m_workerThread, &QThread::deleteLater );
          connect( &m_workerThread, &QThread::finished, worker, &Worker::deleteLater );
          connect( &m_workerThread, &QThread::started,  worker, &Worker::init );
          
          m_workerThread.start();
          
          
          
          MainWindow::~MainWindow()
          {
              qDebug() << "Window deleted";
          
              m_workerThread.quit();
              m_workerThread.wait();
          
              delete m_ui;
          }
          

          I'm also a puzzled about how should I create worker and qthread? Should they be heap allocated? Or can I make them simple member variables? I can't set a parent to a worker class, since it gets moved to thread, but should a qthread have a parent?

          J.HilkJ Offline
          J.HilkJ Offline
          J.Hilk
          Moderators
          wrote on last edited by
          #4

          @Amomum hi,

          Your thought process is solid, but the exmple you posted has a at least one issue that I see:

          you delete your worker and your thread object when worker emit finished -> OK
          but in your destructor you call again quit and wait on an object that is potentially already deleted.

          You can correct that easy enough with a lambda:

          connect( worker, &Worker::finished, worker, [=]{
               worker->deleteLater();
               m_workerThread.quit();
               m_workerThread = Q_NULLPTR;
          });
          
          //instead of 
          connect( worker, &Worker::finished, &m_workerThread, &QThread::quit );
          connect( worker, &Worker::finished, worker, &Worker::deleteLater );
          
          MainWindow::~MainWindow()
          {
              qDebug() << "Window deleted";
          
          if(m_workerThread){
              m_workerThread.quit();
              m_workerThread.wait();
          }
          
              delete m_ui;
          }
          

          There are circular connections bound to your deleteLater stuff, but that should be fine, as Qt removes/disconnects connections whose ref-Object is deleted.


          Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


          Q: What's that?
          A: It's blue light.
          Q: What does it do?
          A: It turns blue.

          1 Reply Last reply
          0
          • raven-worxR raven-worx

            @Amomum
            QThread::quit() only quits it's event-loop -> means when you used QThread::exec() in the run() method.
            QThread::wait() just waits, nothing more.

            So how does your run() implementation look like? You need to make sure that the thread finishes (returns from run()) at some point, since you already connected it's finished signal to deleteLater().

            A Offline
            A Offline
            Amomum
            wrote on last edited by
            #5

            @raven-worx

            QThread::quit() only quits it's event-loop -> means when you used QThread::exec() in the run() method.
            QThread::wait() just waits, nothing more.

            So how does your run() implementation look like? You need to make sure that the thread finishes (returns from run()) at some point, since you already connected it's finished signal to deleteLater().

            I'm not inheriting from QThread, I'm using it as is, so I have no run() implementation.

            @kshegunov

            It should be, when you return control to the thread's event loop (or after the finished() signal). How do you test it exactly?

            I put a qDebug call in it and I put a breakpoint in it. Nothing happens.

            Well, this is wrong. You can allocate whatever you want in the constructor, but you should set the correct parent to your QObject instances, so they get moved with it to the correct thread.

            Oh, so I just have to make them children of my worker. Okay, that's good to know.

            This is suspicious. deleteLater isn't virtual so you probably have overloaded the QObject's slot and thus you don't get your object deleted. Please show a snippet for this piece of your code.

            Probably that was my mistake. My deleteLater is just this:

            void Worker::deleteLater()
            {
                qDebug() << "Worker delete later";
            }
            

            I just commented out this deleteLater and workers destructor is now called. I think that was the issue, thank you!

            Unless you intend to delete it manually (which you do with deleteLater), yes, you should set a parent to it. However, since you create the thread with auto-storage (on the stack) you shouldn't delete it to begin with, the stack will take care to free the memory.

            I'm not intending to delete thread itself in deleteLater, only resources that I will allocate in said thread (i.e. in workers constructor or init).

            @J-Hilk

            you delete your worker and your thread object when worker emit finished -> OK
            but in your destructor you call again quit and wait on an object that is potentially already deleted.

            Hmmm you are correct. Connecting workers finished and threads quit was a mistake by copy-pasting. Any way, my worker won't emit finished (and it doesn't right now), so the problem lies elsewhere.

            raven-worxR kshegunovK 2 Replies Last reply
            0
            • A Amomum

              @raven-worx

              QThread::quit() only quits it's event-loop -> means when you used QThread::exec() in the run() method.
              QThread::wait() just waits, nothing more.

              So how does your run() implementation look like? You need to make sure that the thread finishes (returns from run()) at some point, since you already connected it's finished signal to deleteLater().

              I'm not inheriting from QThread, I'm using it as is, so I have no run() implementation.

              @kshegunov

              It should be, when you return control to the thread's event loop (or after the finished() signal). How do you test it exactly?

              I put a qDebug call in it and I put a breakpoint in it. Nothing happens.

              Well, this is wrong. You can allocate whatever you want in the constructor, but you should set the correct parent to your QObject instances, so they get moved with it to the correct thread.

              Oh, so I just have to make them children of my worker. Okay, that's good to know.

              This is suspicious. deleteLater isn't virtual so you probably have overloaded the QObject's slot and thus you don't get your object deleted. Please show a snippet for this piece of your code.

              Probably that was my mistake. My deleteLater is just this:

              void Worker::deleteLater()
              {
                  qDebug() << "Worker delete later";
              }
              

              I just commented out this deleteLater and workers destructor is now called. I think that was the issue, thank you!

              Unless you intend to delete it manually (which you do with deleteLater), yes, you should set a parent to it. However, since you create the thread with auto-storage (on the stack) you shouldn't delete it to begin with, the stack will take care to free the memory.

              I'm not intending to delete thread itself in deleteLater, only resources that I will allocate in said thread (i.e. in workers constructor or init).

              @J-Hilk

              you delete your worker and your thread object when worker emit finished -> OK
              but in your destructor you call again quit and wait on an object that is potentially already deleted.

              Hmmm you are correct. Connecting workers finished and threads quit was a mistake by copy-pasting. Any way, my worker won't emit finished (and it doesn't right now), so the problem lies elsewhere.

              raven-worxR Offline
              raven-worxR Offline
              raven-worx
              Moderators
              wrote on last edited by
              #6

              @Amomum said in QThread creation and cleanup:

              I'm not inheriting from QThread, I'm using it as is, so I have no run() implementation.

              ?????
              Then where does m_workerThread come from?!

              --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
              If you have a question please use the forum so others can benefit from the solution in the future

              A 1 Reply Last reply
              0
              • raven-worxR raven-worx

                @Amomum said in QThread creation and cleanup:

                I'm not inheriting from QThread, I'm using it as is, so I have no run() implementation.

                ?????
                Then where does m_workerThread come from?!

                A Offline
                A Offline
                Amomum
                wrote on last edited by
                #7

                @raven-worx said in QThread creation and cleanup:

                ?????
                Then where does m_workerThread come from?!

                That's just a QThread object inside of my MainWindow class.
                I'm not inheriting from QThread, I create a QThread object, worker object and I move worker into qthread. As far as I know that's one of the recommended ways of using qthread and since I need a thread that will live as long as the whole app does (and probably will need to handle events) I chose it instead of inhereting from qthread and reimplementing run().

                1 Reply Last reply
                0
                • A Amomum

                  @raven-worx

                  QThread::quit() only quits it's event-loop -> means when you used QThread::exec() in the run() method.
                  QThread::wait() just waits, nothing more.

                  So how does your run() implementation look like? You need to make sure that the thread finishes (returns from run()) at some point, since you already connected it's finished signal to deleteLater().

                  I'm not inheriting from QThread, I'm using it as is, so I have no run() implementation.

                  @kshegunov

                  It should be, when you return control to the thread's event loop (or after the finished() signal). How do you test it exactly?

                  I put a qDebug call in it and I put a breakpoint in it. Nothing happens.

                  Well, this is wrong. You can allocate whatever you want in the constructor, but you should set the correct parent to your QObject instances, so they get moved with it to the correct thread.

                  Oh, so I just have to make them children of my worker. Okay, that's good to know.

                  This is suspicious. deleteLater isn't virtual so you probably have overloaded the QObject's slot and thus you don't get your object deleted. Please show a snippet for this piece of your code.

                  Probably that was my mistake. My deleteLater is just this:

                  void Worker::deleteLater()
                  {
                      qDebug() << "Worker delete later";
                  }
                  

                  I just commented out this deleteLater and workers destructor is now called. I think that was the issue, thank you!

                  Unless you intend to delete it manually (which you do with deleteLater), yes, you should set a parent to it. However, since you create the thread with auto-storage (on the stack) you shouldn't delete it to begin with, the stack will take care to free the memory.

                  I'm not intending to delete thread itself in deleteLater, only resources that I will allocate in said thread (i.e. in workers constructor or init).

                  @J-Hilk

                  you delete your worker and your thread object when worker emit finished -> OK
                  but in your destructor you call again quit and wait on an object that is potentially already deleted.

                  Hmmm you are correct. Connecting workers finished and threads quit was a mistake by copy-pasting. Any way, my worker won't emit finished (and it doesn't right now), so the problem lies elsewhere.

                  kshegunovK Offline
                  kshegunovK Offline
                  kshegunov
                  Moderators
                  wrote on last edited by
                  #8

                  @Amomum said in QThread creation and cleanup:

                  Oh, so I just have to make them children of my worker.

                  Indeed. So you can still create your timer in the constructor of the worker, just set its parent to the worker object. I usually also opt for using the stack for this, cause, well I'm a stack fan ... ;)
                  E.g.

                  class Worker : public QObject
                  {
                      Q_OBJECT
                  
                  public:
                      Worker()
                          : QObject(), timer(this) //< It's enough to set the parent so the timer be moved to the thread of the worker object
                      {
                      }
                  
                  private:
                      QTimer timer;
                  };
                  

                  I'm not intending to delete thread itself in deleteLater, only resources that I will allocate in said thread (i.e. in workers constructor or init).

                  Well, then put whatever you want to clean up in the destructor. If that's not sufficient for some reason (although it'd be my preference), you can create your own slot, for example public slots: void Worker::freeResources(); and connect that to the finished() signal instead. deleteLater() is when you need the object to be deleted, so don't use it in this case.

                  @Amomum said in QThread creation and cleanup:

                  @J-Hilk
                  but in your destructor you call again quit and wait on an object that is potentially already deleted.

                  Connecting workers finished and threads quit was a mistake by copy-pasting.

                  No, that's fine. The worker may want to quit ahead of time. And there is no problem with this approach. The only issue is you're requesting your thread object be deleted through the deleteLater slot, which will cause segfault, because you'd be trying to delete an object that's created on the stack.

                  Read and abide by the Qt Code of Conduct

                  A 1 Reply Last reply
                  1
                  • kshegunovK kshegunov

                    @Amomum said in QThread creation and cleanup:

                    Oh, so I just have to make them children of my worker.

                    Indeed. So you can still create your timer in the constructor of the worker, just set its parent to the worker object. I usually also opt for using the stack for this, cause, well I'm a stack fan ... ;)
                    E.g.

                    class Worker : public QObject
                    {
                        Q_OBJECT
                    
                    public:
                        Worker()
                            : QObject(), timer(this) //< It's enough to set the parent so the timer be moved to the thread of the worker object
                        {
                        }
                    
                    private:
                        QTimer timer;
                    };
                    

                    I'm not intending to delete thread itself in deleteLater, only resources that I will allocate in said thread (i.e. in workers constructor or init).

                    Well, then put whatever you want to clean up in the destructor. If that's not sufficient for some reason (although it'd be my preference), you can create your own slot, for example public slots: void Worker::freeResources(); and connect that to the finished() signal instead. deleteLater() is when you need the object to be deleted, so don't use it in this case.

                    @Amomum said in QThread creation and cleanup:

                    @J-Hilk
                    but in your destructor you call again quit and wait on an object that is potentially already deleted.

                    Connecting workers finished and threads quit was a mistake by copy-pasting.

                    No, that's fine. The worker may want to quit ahead of time. And there is no problem with this approach. The only issue is you're requesting your thread object be deleted through the deleteLater slot, which will cause segfault, because you'd be trying to delete an object that's created on the stack.

                    A Offline
                    A Offline
                    Amomum
                    wrote on last edited by
                    #9

                    @kshegunov said in QThread creation and cleanup:

                    No, that's fine. The worker may want to quit ahead of time. And there is no problem with this approach. The only issue is you're requesting your thread object be deleted through the deleteLater slot, which will cause segfault, because you'd be trying to delete an object that's created on the stack.

                    Hmm. So if I create my Qthread object on the stack (more precisely, as a member of MainWindow, but mainwindow object is created on the stack of main), I should not call quit() and wait(), I can just do nothing and Qthread dtor will be called automatically after main will exit (and it will call workers dtor)? Will that be okay?

                    1 Reply Last reply
                    0
                    • A Offline
                      A Offline
                      Amomum
                      wrote on last edited by
                      #10

                      @kshegunov
                      Oh, I got it, sorry. I need to quit the thread and wait for it to quit. The problem will be if my worker will emit finished, thread will quit and then I close my mainwindow and try to quit the thread again. I shouldn't do that.
                      Thank you!

                      kshegunovK 1 Reply Last reply
                      0
                      • A Amomum

                        @kshegunov
                        Oh, I got it, sorry. I need to quit the thread and wait for it to quit. The problem will be if my worker will emit finished, thread will quit and then I close my mainwindow and try to quit the thread again. I shouldn't do that.
                        Thank you!

                        kshegunovK Offline
                        kshegunovK Offline
                        kshegunov
                        Moderators
                        wrote on last edited by
                        #11

                        @Amomum said in QThread creation and cleanup:

                        I need to quit the thread and wait for it to quit.

                        Yes, you do, this is not optional.

                        The problem will be if my worker will emit finished, thread will quit and then I close my mainwindow and try to quit the thread again. I shouldn't do that.

                        This is not a problem. You can quit muiltiple times safely and wait() will block only if the thread's running.

                        Read and abide by the Qt Code of Conduct

                        1 Reply Last reply
                        1

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved