QObject: Cannot create children for a parent that is in a different thread
Asked Answered
B

6

7

EDIT:

I tried doing what you guys told me in comments ... :

Citizen * c = new Citizen(this);

QThread thread;
c->moveToThread(&thread);

connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();

This produces even more errors:

QThread: Destroyed while thread is still running
ASSERT failure in QThread::setTerminationEnabled(): "Current thread was not started with QThread.", file c:\ndk_buildrepos\qt-desktop\src\corelib\thread\qthread_win.cpp, line 542
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
QObject::killTimers: timers cannot be stopped from another thread

I am having problems with this error ... I'm stuck on this for 2 days already and can't get a solution.

Header:

class Citizen : public QThread
{
Q_OBJECT    
    QNetworkAccessManager * manager;

private slots:
    void onReplyFinished(QNetworkReply* net_reply);

public:
    Citizen(QObject * parent);

    void run();
};

Implementation:

Citizen::Citizen(QObject * parent)
{
    manager = new QNetworkAccessManager;
    connect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(onReplyFinished(QNetworkReply*)));
}

void Citizen::onReplyFinished(QNetworkReply* net_reply)
{
    emit onFinished(net_reply);
}

void Citizen::run()
{
    manager->get(QNetworkRequest(QUrl("http://google.com"));

    QEventLoop eLoop;
    connect(manager, SIGNAL( finished( QNetworkReply * ) ), &eLoop, SLOT(quit()));
    eLoop.exec(QEventLoop::ExcludeUserInputEvents);

    qDebug() << "loaded google!";

    exec();
}

When manager->get() gets executed, I get the following error:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0xc996cf8), parent's thread is QThread(0xaba48d8), current thread is Citizen(0xca7ae08)

When eLoop.exec() gets executed:

QObject::startTimer: timers cannot be started from another thread

I start this thread in the following manner:

Citizen * c = new Citizen(this);
c->start();

Why does this happen? How to solve this?

Bipack answered 1/8, 2011 at 15:49 Comment(1)
There is a good article for this subject Threads, Events and QObjects. If your class Citizen works in a thread you should not inherit it from QThread, because the purpose of inheritance from QThread is not to do some job in the thread, but manage the thread.Curch
C
3

I will just try to answer why you are seeing QThread: Destroyed while thread is still running error.

If you do this

void mtMethod () {

 Citizen * c = new Citizen(this);
 QThread thread;
 c->moveToThread(&thread);

 connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
 thread.start();
}

The thread object will be destroyed when you exit the function but the thread that has been started is still running !. Qt is warning you that you should either stop the thread or create the thread object in a bigger scope. (i.e make it a member function of your class). Something like this :

class myClass
{
virtual ~myClass ();
 QThread mythread;
};

myClass::~myClass
{
  mythread.stop ();
}

void myClass::mtMethod () {

     Citizen * c = new Citizen(this);
     c->moveToThread(&mythread);

     connect(&mythread, SIGNAL(started()), c, SLOT(ProcessActions()));
     mythread.start();
}
Chevy answered 2/8, 2011 at 6:14 Comment(1)
Assigning a parent to an object that is then moved to another thread is a no go. This answer is incorrect. @Kim Bowles Sørhus's answer is the one that should be marked as such.Hulbard
T
12
QObject: Cannot create children for a parent that is in a different thread.

You get this because you are creating the QNetworkAccessmanager in the constructor of Citizen, which is being called in the "original" thread. When the Citizen object is moved to the new thread the QNetworkAccessmanager still has its thread affinity set to the original thread but in the run call it will attempt to create the QNetworkReply object ( and probably other objects aswell ) in the new thread. Which produces the warning above.

If you create the manager in the run slot(or at any point after the Citizen object is moved to the new thread) that will not happen.

However you still have some issues. For instance, the Citizen class really doesn't need to be a QThread. It needlessly complicates it. It will suffice for your purpose(afaict) to subclass a QObject. Just make a normal slot and connect that to the QThread::started() signal. And as OrcunC pointed out you need to make sure that the QThread instance is properly scoped.

For more on threading: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/

Example:

QThread *thread = new QThread;
thread->start();
Citizen *worker = new Citizen;
worker->moveToThread(thread);

//startWorking can be equivalent of the run function
//in your current implementation and this is where you should
//create the QNetworkAccessManager
QMetaObject::invokeMethod(worker,"startWorking");
Togoland answered 2/8, 2011 at 10:21 Comment(0)
C
3

I will just try to answer why you are seeing QThread: Destroyed while thread is still running error.

If you do this

void mtMethod () {

 Citizen * c = new Citizen(this);
 QThread thread;
 c->moveToThread(&thread);

 connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
 thread.start();
}

The thread object will be destroyed when you exit the function but the thread that has been started is still running !. Qt is warning you that you should either stop the thread or create the thread object in a bigger scope. (i.e make it a member function of your class). Something like this :

class myClass
{
virtual ~myClass ();
 QThread mythread;
};

myClass::~myClass
{
  mythread.stop ();
}

void myClass::mtMethod () {

     Citizen * c = new Citizen(this);
     c->moveToThread(&mythread);

     connect(&mythread, SIGNAL(started()), c, SLOT(ProcessActions()));
     mythread.start();
}
Chevy answered 2/8, 2011 at 6:14 Comment(1)
Assigning a parent to an object that is then moved to another thread is a no go. This answer is incorrect. @Kim Bowles Sørhus's answer is the one that should be marked as such.Hulbard
O
1

I don't believe the new thread exists until run is called. So the constructor is a different thread than run(). What happens if you move the creation of the manager object from the constructor to run()? I imagine that will fix the first error, if not the timer error as well.

Also, I think many people are still building threads the way you are, but you might want to check out this.

Orsola answered 1/8, 2011 at 16:2 Comment(7)
Doesn't work, I also checked out that blog post. Check my question.Bipack
Which didn't work? Moving the creation of manager out of the constructor, or using moveToThread in the way the link discusses? I don't think your edit is correct. If you use Citizen as the object that is moved to a QThread, Citizen should not derive from QThread.Orsola
first, your QThread, created on a stack, destroys after you exit subroutine, that starts thread. You don't want this, I suppose. You should make QThread a member of a class. Then, you needn't explicitly call quit method. Your thread will stop when exec return.Encamp
@Brett Stottlemyer Moving the creation of manager out of the constructor didn't work. Neither did moveToThread, but as you pointed out I might be using it incorrectly. I Will try it your way.Bipack
@Brett I made the Citizen class a QObject, but it is still not working.Bipack
@Encamp I don't understand how exactly to make QThread a member of a class?Bipack
All code, that creates thread is a function of some class, doesn't it? When that return, created thread will be destroyed, because your thread is local variable. You should move your thread definition out of this functionEncamp
B
1

You need to consider thread affinity. That error message is not lying or insane, it's telling you exactly what's wrong.

Bornstein answered 1/8, 2011 at 16:5 Comment(1)
your link is dead.Rittenhouse
A
1

Your problems are mostly due to trying to subclass QThread. Even though the documentation recommends it, it is not the best way to use QThread. Please see this question and answer for more information and links.

Alcoholize answered 1/8, 2011 at 16:6 Comment(0)
R
1

I haven't figured out the startTimers error although it could be related to the first one. In any case, you should be able to fix the first error. I have run into this problem in Qt a few times and I find this to be the "best" way to work around it is to create an initialize function and a cleanUp function. All members of the class are pointers that are initialized to NULL until run is called. Note that "best" is in quotes because there are sure to be differing opinions but it works for most situations for me.

Header

class Citizen : public QThread {
   Q_OBJECT

   QNetworkAccessManager * manager;

   private slots:
      void onReplyFinished(QNetworkReply* net_reply);
   public:
      Citizen(QObject * parent);
      void run();

   private:
      void initialize();
      void cleanUp();
 };

Implementation

Citizen::Citizen(QObject * parent) :
   manager(NULL) {
}

void Citizen::onReplyFinished(QNetworkReply* net_reply) {
   emit onFinished(net_reply);
}

void Citizen::run() {
   initialize();
   manager->get(QNetworkRequest(QUrl("http://google.com"));

   QEventLoop eLoop;
   connect(manager, SIGNAL( finished( QNetworkReply * ) ),
           &eLoop, SLOT(quit()));
   eLoop.exec(QEventLoop::ExcludeUserInputEvents);

   qDebug() << "loaded google!";
   exec();

   cleanUp();
}

void Citizen::initialize() {
   manager = new QNetworkAccessManager;
   connect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
           this, SLOT(onReplyFinished(QNetworkReply*)));
}

void Citizen::cleanUp() {
   delete manager;
   disconnect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
              this, SLOT(onReplyFinished(QNetworkReply*)));
}
Rakes answered 1/8, 2011 at 22:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.