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. Create a QObject in another thread, retrieve it to the current thread and set a parent = ASSERT failure in Debug on msvc16
QtWS25 Last Chance

Create a QObject in another thread, retrieve it to the current thread and set a parent = ASSERT failure in Debug on msvc16

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 2 Posters 1.9k 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.
  • N Offline
    N Offline
    NiHoTleHot
    wrote on last edited by
    #1

    Hi everyone,
    I am just trying to set a parent on a QObject created in another thread (the object is of course moved to the parent thread before), that's all !

    #include <QApplication>
    #include <QDebug>
    #include <QThread>
    
    class Thread : public QThread //Just a convenient Class using a lambda
    {
    public:
        Thread::Thread(QObject *parent = nullptr) : QThread(parent){}
        std::function<void()> todo;
    protected:
        virtual void run() override{
            todo();
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        ///////////////////////////////////////////////
        // Change this flag to switch behaviours
        bool tryToSetParentInThread = true;
        ///////////////////////////////////////////////
    
        QObject mainObj;
        QObject *dummy; //Just to get back obj created in thread;
    
        Thread thread;
        thread.todo = [&](){
            //QObject *obj = new QObject(&mainObj); //"QObject: Cannot create children for a parent that is in a different thread." ! Of course!
    
            // So we try this
            QObject *obj = new QObject;
            dummy = obj;
    
            qDebug()<<obj->thread();
            obj->moveToThread(mainObj.thread());
            qDebug()<<obj->thread(); //Check that the Thread affinity change is done
    
            if(tryToSetParentInThread)
                obj->setParent(&mainObj);
    
            QObject::connect(obj, &QObject::destroyed, [](){ //Parent mecanism is OK
                qDebug()<<"Child destroyed";
            });
        };
        thread.start();
        thread.wait();
    
        if(!tryToSetParentInThread)
            dummy->setParent(&mainObj);
    
        return 0; //No need for an event loop here
    }
    

    This example is working fine in release, but if you try to launch this code in debug with mscv16:

    799a3782-874c-4339-bfde-dff6c420abf0-image.png
    Maybe the call of obj->setParent(&mainObj) doesn't like that mainObj is not in the thread calling the method ..?

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #6

      You're accessing a QObject and doing a lot of stuff with it inside another thread - that this will crash sooner or later should be clear.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      1
      • Christian EhrlicherC Offline
        Christian EhrlicherC Offline
        Christian Ehrlicher
        Lifetime Qt Champion
        wrote on last edited by
        #2

        You can't set a parent which is not in the same thread.

        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
        Visit the Qt Academy at https://academy.qt.io/catalog

        N 1 Reply Last reply
        0
        • Christian EhrlicherC Christian Ehrlicher

          You can't set a parent which is not in the same thread.

          N Offline
          N Offline
          NiHoTleHot
          wrote on last edited by NiHoTleHot
          #3

          @Christian-Ehrlicher Of course ! This is not what I am doing here !
          The objects have the same thread affinity when I do the setParent()
          You can see a commented line of what I am not doing :-D
          50d0b760-71c1-43aa-86ba-fe57f727051c-image.png

          1 Reply Last reply
          0
          • Christian EhrlicherC Offline
            Christian EhrlicherC Offline
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #4

            But you're calling the QObject function from another thread which creates an event in the thread where the object does not life in and therefore the assert

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            N 1 Reply Last reply
            2
            • Christian EhrlicherC Christian Ehrlicher

              But you're calling the QObject function from another thread which creates an event in the thread where the object does not life in and therefore the assert

              N Offline
              N Offline
              NiHoTleHot
              wrote on last edited by NiHoTleHot
              #5

              @Christian-Ehrlicher That is what I supposed "Maybe the call of obj->setParent(&mainObj) doesn't like that mainObj is not in the thread calling the method ..?"
              So obj1->setParent(obj2) triggers a sendEvent() ? No mention of that in documentation !!
              But if it does, it is weird to not check thread affinity and replace the sendEvent() by a postEvent() :-(

              Edit :
              @Christian-Ehrlicher This really ugly but indeed it worked, I had to force the execution of the setParent() in the main thread via a queued connection in the thread. And of course start the eventloop in the main thread

              #include <QApplication>
              #include <QDebug>
              #include <QThread>
              #include <QTimer>
              
              class Thread : public QThread //Just a convenient Class using a lambda
              {
              public:
                  Thread::Thread(QObject *parent = nullptr) : QThread(parent){}
                  std::function<void()> todo;
              protected:
                  virtual void run() override{
                      todo();
                  }
              };
              
              int main(int argc, char *argv[])
              {
                  QApplication a(argc, argv);
              
                  ///////////////////////////////////////////////
                  // Change this flag to switch behaviours
                  bool tryToSetParentInThread = true;
                  ///////////////////////////////////////////////
              
                  QObject mainObj;
              
                  Thread thread;
                  thread.todo = [&](){
                      //QObject *obj = new QObject(&mainObj); //"QObject: Cannot create children for a parent that is in a different thread." ! Of course!
              
                      // So we try this
                      QObject *obj = new QObject;
              
                      qDebug()<<obj->thread();
                      obj->moveToThread(mainObj.thread());
                      qDebug()<<obj->thread(); //Check that the Thread affinity change is done
              
              
                     QObject::connect(QThread::currentThread(), &QThread::finished, obj, [obj,&mainObj](){
                         qDebug()<<"Most fucked up code I wrote";
                         obj->setParent(&mainObj);
                      });
              
              
              
                      QObject::connect(obj, &QObject::destroyed, [](){ //Parent mecanism is OK
                          qDebug()<<"Child destroyed";
                      });
                  };
                  thread.start();
                  thread.wait();
              
                  QTimer::singleShot(0,[](){
                      qApp->quit();
                  });
              
                  return a.exec(); //Add an event loop for the connect (queued) from the thread -> setParent() triggers a SendEvent() in the main thread where the two object now live
              }
              
              1 Reply Last reply
              0
              • Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #6

                You're accessing a QObject and doing a lot of stuff with it inside another thread - that this will crash sooner or later should be clear.

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                1 Reply Last reply
                1
                • N Offline
                  N Offline
                  NiHoTleHot
                  wrote on last edited by
                  #7

                  So I debugged qt lib, the problem comes from setParent() doing a sendEvent() without checking the thread affinity. This is simply a bug.
                  Depending on the calling thread it should make a postevent() instead
                  cd79e018-a4ac-43bd-8878-9c53147f0f87-image.png
                  I ve just replace obj->setParent(&mainObj); by

                  QMetaObject::invokeMethod(&mainObj, [&mainObj, obj](){
                      obj->setParent(&mainObj);
                  });
                  

                  The invokeMethod() execute setParent in the correct.

                  1 Reply Last reply
                  0
                  • Christian EhrlicherC Offline
                    Christian EhrlicherC Offline
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on last edited by
                    #8

                    @NiHoTleHot said in Create a QObject in another thread, retrieve it to the current thread and set a parent = ASSERT failure in Debug on msvc16:

                    This is simply a bug.

                    No, you're modifying an object which lives in another thread - it may work or it may crash.

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    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