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. ConnectionType for connection between QThread::finished and QObject::deleteLater
Forum Updated to NodeBB v4.3 + New Features

ConnectionType for connection between QThread::finished and QObject::deleteLater

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 2 Posters 1.1k Views 1 Watching
  • 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.
  • F Offline
    F Offline
    Fran Sansone
    wrote on last edited by
    #1

    I have this simple piece of code:

    A simple qobject:

    #include <QObject>
    
    class A : public QObject
    {
        Q_OBJECT
    public:
        A();
    
        virtual ~A();
    
        void start();
    signals:
        void finished();
    };
    
    #include "a.h"
    
    #include <QDebug>
    #include <QThread>
    
    A::A()
    {
    
    }
    
    A::~A(){ qInfo() << "A deleted in thread " << QThread::currentThread(); }
    
    void A::start() { qInfo() << "do stuf..."; emit finished(); }
    
    

    A main where the qobject is created and run in a secondary thread:

    #include <QCoreApplication>
    #include <QDebug>
    #include <QThread>
    #include <QObject>
    
    #include "a.h"
    
    
    int main(int argc, char *argv[])
    {
        QCoreApplication app(argc, argv);
    
        qInfo()  << "Main running in " << QThread::currentThread();
    
        QThread *t = new QThread();
        A* a = new A;
        a->moveToThread(t);
        QObject::connect(t, &QThread::started, a, &A::start);
        QObject::connect(t, &QThread::finished, a, &A::deleteLater, Qt::QueuedConnection);
        //    QObject::connect(t, &QThread::finished, a, &A::deleteLater, Qt::DirectConnection);
        QObject::connect(a, &A::finished, [t]() { t->exit(0); });
    
        t->start();
    
        qInfo() << "t lives in " << t->currentThread();
    
        return app.exec();
    }
    
    

    The connections between QThread and A elements should be QueuedConnection due to they live in different threads, but if the ConnectionType of QThread::finished and QObject::deleteLater connection is QueuedConnection, the object deleter will be never called.
    If the ConnectionType of that connection is DirectConnection, a is deleted in its thread even though it should be executed on the main thread. Is this a bug with the event loop?

    This is the output of calling with DirectConnection:

    Main running in  QThread(0x559f7c6c3e60)
    t lives in  QThread(0x559f7c6c3e60)
    do stuf... in thread  QThread(0x559f7c6c9540)
    A deleted in thread  QThread(0x559f7c6c9540)
    
    KroMignonK 1 Reply Last reply
    0
    • F Fran Sansone

      I have this simple piece of code:

      A simple qobject:

      #include <QObject>
      
      class A : public QObject
      {
          Q_OBJECT
      public:
          A();
      
          virtual ~A();
      
          void start();
      signals:
          void finished();
      };
      
      #include "a.h"
      
      #include <QDebug>
      #include <QThread>
      
      A::A()
      {
      
      }
      
      A::~A(){ qInfo() << "A deleted in thread " << QThread::currentThread(); }
      
      void A::start() { qInfo() << "do stuf..."; emit finished(); }
      
      

      A main where the qobject is created and run in a secondary thread:

      #include <QCoreApplication>
      #include <QDebug>
      #include <QThread>
      #include <QObject>
      
      #include "a.h"
      
      
      int main(int argc, char *argv[])
      {
          QCoreApplication app(argc, argv);
      
          qInfo()  << "Main running in " << QThread::currentThread();
      
          QThread *t = new QThread();
          A* a = new A;
          a->moveToThread(t);
          QObject::connect(t, &QThread::started, a, &A::start);
          QObject::connect(t, &QThread::finished, a, &A::deleteLater, Qt::QueuedConnection);
          //    QObject::connect(t, &QThread::finished, a, &A::deleteLater, Qt::DirectConnection);
          QObject::connect(a, &A::finished, [t]() { t->exit(0); });
      
          t->start();
      
          qInfo() << "t lives in " << t->currentThread();
      
          return app.exec();
      }
      
      

      The connections between QThread and A elements should be QueuedConnection due to they live in different threads, but if the ConnectionType of QThread::finished and QObject::deleteLater connection is QueuedConnection, the object deleter will be never called.
      If the ConnectionType of that connection is DirectConnection, a is deleted in its thread even though it should be executed on the main thread. Is this a bug with the event loop?

      This is the output of calling with DirectConnection:

      Main running in  QThread(0x559f7c6c3e60)
      t lives in  QThread(0x559f7c6c3e60)
      do stuf... in thread  QThread(0x559f7c6c9540)
      A deleted in thread  QThread(0x559f7c6c9540)
      
      KroMignonK Offline
      KroMignonK Offline
      KroMignon
      wrote on last edited by
      #2

      @Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:

      but if the ConnectionType of QThread::finished and QObject::deleteLater connection is QueuedConnection, the object deleter will be never called.

      This is normal, QObject::deleteLater() while schedule the deletion of the instance in the event queue to be executed on next iteration in event queue. This will ensure deletion will be done in instance working thread!
      (cf. https://doc.qt.io/qt-5/qobject.html#deleteLater).

      To do it in the right order, deleteLater() should be called before emitting finished signal.

      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

      F 1 Reply Last reply
      0
      • KroMignonK KroMignon

        @Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:

        but if the ConnectionType of QThread::finished and QObject::deleteLater connection is QueuedConnection, the object deleter will be never called.

        This is normal, QObject::deleteLater() while schedule the deletion of the instance in the event queue to be executed on next iteration in event queue. This will ensure deletion will be done in instance working thread!
        (cf. https://doc.qt.io/qt-5/qobject.html#deleteLater).

        To do it in the right order, deleteLater() should be called before emitting finished signal.

        F Offline
        F Offline
        Fran Sansone
        wrote on last edited by
        #3

        @KroMignon Thank you for your response.

        According to qt documentation about QThread::finished:

        When this signal is emitted, the event loop has already stopped running. No more events will be processed in the thread, except for deferred deletion events. This signal can be connected to QObject::deleteLater(), to free objects in that thread.
        

        This is why I find confusing this behavior. I understand that the connection is OK (using QueuedConnection) and the deletion should be executed in the secondary thread (a's thread).

        KroMignonK 1 Reply Last reply
        0
        • F Fran Sansone

          @KroMignon Thank you for your response.

          According to qt documentation about QThread::finished:

          When this signal is emitted, the event loop has already stopped running. No more events will be processed in the thread, except for deferred deletion events. This signal can be connected to QObject::deleteLater(), to free objects in that thread.
          

          This is why I find confusing this behavior. I understand that the connection is OK (using QueuedConnection) and the deletion should be executed in the secondary thread (a's thread).

          KroMignonK Offline
          KroMignonK Offline
          KroMignon
          wrote on last edited by
          #4

          @Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:

          This is why I find confusing this behavior. I understand that the connection is OK (using QueuedConnection) and the deletion should be executed in the secondary thread (a's thread).

          I don't understand what is confusing here?.
          QThread t is emitting finished(), which means the thread has stopped.
          You could use this signal to connect to deleteLater() on instance t to also delete the thread instance (because this instance lives in the main thread) but not for a (or you have to use Qt::DirectConnection).

          It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

          F 1 Reply Last reply
          0
          • KroMignonK KroMignon

            @Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:

            This is why I find confusing this behavior. I understand that the connection is OK (using QueuedConnection) and the deletion should be executed in the secondary thread (a's thread).

            I don't understand what is confusing here?.
            QThread t is emitting finished(), which means the thread has stopped.
            You could use this signal to connect to deleteLater() on instance t to also delete the thread instance (because this instance lives in the main thread) but not for a (or you have to use Qt::DirectConnection).

            F Offline
            F Offline
            Fran Sansone
            wrote on last edited by Fran Sansone
            #5

            @KroMignon I want to delete a. QThread::finished signal is emitted from the main thread and I want to connect it to A:deleteLater with a object as receiver, which lives in another thread. So, I understand, I should use QueuedConnection for this case (to execute it in the receiver's thread), but it doesn't work.
            Instead, it works if I use DirectConnection, even though the signal is emitted in the main thread and the slot is executed in another thread (DirectConnection should execute the slot in the sender's thread).

            KroMignonK 1 Reply Last reply
            0
            • F Fran Sansone

              @KroMignon I want to delete a. QThread::finished signal is emitted from the main thread and I want to connect it to A:deleteLater with a object as receiver, which lives in another thread. So, I understand, I should use QueuedConnection for this case (to execute it in the receiver's thread), but it doesn't work.
              Instead, it works if I use DirectConnection, even though the signal is emitted in the main thread and the slot is executed in another thread (DirectConnection should execute the slot in the sender's thread).

              KroMignonK Offline
              KroMignonK Offline
              KroMignon
              wrote on last edited by KroMignon
              #6

              @Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:

              I want to delete a. QThread::finished signal is emitted from the main thread and I want to connect it to A:deleteLater with a object as receiver, which lives in another thread.

              You doing things in the wrong order.
              You should always delete the object in the thread in which they are running.
              This means deleting a before stopping thread t.

                  QThread *t = new QThread();
                  A* a = new A;
                  a->moveToThread(t);
                  // on thread start, start worker
                  QObject::connect(t, &QThread::started, a, &A::start);
                  // on worker done, delete worker
                  QObject::connect(a, &A::finished, a, &A::deleteLater);
                  // on worker deleted, stop worker thread
                  QObject::connect(a, &QObject::destroyed, t, &QThread::quit); 
                  // on threa end, delete thread
                  QObject::connect(t, &QObject::finished, t, &QThread::delteLater); 
              
                 t->start();
              

              [EDIT]:
              I made an error, to QObject::destroyed() only works with Qt::DirectConnection because direct after calling all connection with instance are destroyed (cf. https://doc.qt.io/qt-5/qobject.html#destroyed)

              QObject::connect(a, &QObject::destroyed, t, &QThread::quit, Qt::DirectConnection); 
              

              A better way, would be to change as follow

               QObject::connect(a, &A::finished, a, &A::deleteLater);
               QObject::connect(a, &A::finished, t, &QThread::quit);
              

              It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

              F 1 Reply Last reply
              0
              • KroMignonK KroMignon

                @Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:

                I want to delete a. QThread::finished signal is emitted from the main thread and I want to connect it to A:deleteLater with a object as receiver, which lives in another thread.

                You doing things in the wrong order.
                You should always delete the object in the thread in which they are running.
                This means deleting a before stopping thread t.

                    QThread *t = new QThread();
                    A* a = new A;
                    a->moveToThread(t);
                    // on thread start, start worker
                    QObject::connect(t, &QThread::started, a, &A::start);
                    // on worker done, delete worker
                    QObject::connect(a, &A::finished, a, &A::deleteLater);
                    // on worker deleted, stop worker thread
                    QObject::connect(a, &QObject::destroyed, t, &QThread::quit); 
                    // on threa end, delete thread
                    QObject::connect(t, &QObject::finished, t, &QThread::delteLater); 
                
                   t->start();
                

                [EDIT]:
                I made an error, to QObject::destroyed() only works with Qt::DirectConnection because direct after calling all connection with instance are destroyed (cf. https://doc.qt.io/qt-5/qobject.html#destroyed)

                QObject::connect(a, &QObject::destroyed, t, &QThread::quit, Qt::DirectConnection); 
                

                A better way, would be to change as follow

                 QObject::connect(a, &A::finished, a, &A::deleteLater);
                 QObject::connect(a, &A::finished, t, &QThread::quit);
                
                F Offline
                F Offline
                Fran Sansone
                wrote on last edited by
                #7

                Thank you very much @KroMignon.

                It works properly with your last example.

                I can add to this conversation that the connection that in my code this connection was wrong:

                 QObject::connect(a, &A::finished, [t]() { t->exit(0); });
                

                Changing this connection for:

                QObject::connect(a, &A::finished, t, &QThread::quit);
                

                and the deletion using QueuedConnection that I was mentioning works properly.

                1 Reply Last reply
                0

                • Login

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