QObject:无法为处于不同线程中的父级创建子级

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

本文关键字:线程 创建 于不同 QObject      更新时间:2023-10-16

编辑:

我试着做你们在评论中告诉我的…:

Citizen * c = new Citizen(this);
QThread thread;
c->moveToThread(&thread);
connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();

这会产生更多的错误:

QThread: Destroyed while thread is still running
ASSERT failure in QThread::setTerminationEnabled(): "Current thread was not started with QThread.", file c:ndk_buildreposqt-desktopsrccorelibthreadqthread_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

我对这个错误有问题。。。我已经被这个问题困扰了两天,无法找到解决方案。

标题:

class Citizen : public QThread
{
Q_OBJECT    
    QNetworkAccessManager * manager;
private slots:
    void onReplyFinished(QNetworkReply* net_reply);
public:
    Citizen(QObject * parent);
    void run();
};

实施:

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();
}

当manager->get((被执行时,我得到以下错误:

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)

当执行eLoop.exec((时:

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

我以以下方式启动此线程:

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

为什么会发生这种情况?如何解决这个问题?

QObject: Cannot create children for a parent that is in a different thread.

之所以会出现这种情况,是因为您正在Citizen的构造函数中创建QNetworkAccessmanager,该构造函数在"原始"线程中被调用。当Citizen对象移动到新线程时,QNetworkAccessmanager仍然将其线程关联设置为原始线程,但在运行调用中,它将尝试在新线程中创建QNetworkReply对象(可能还有其他对象(。这就产生了上面的警告。

如果您在运行槽中创建管理器(或者在Citizen对象移动到新线程后的任何时候(,则不会发生这种情况。

但是,您仍然有一些问题。例如,Citizen类实际上不需要是QThread。它不必要地使它复杂化。对你的目的(afaict(来说,子类化一个QObject就足够了。只需制作一个普通插槽,并将其连接到QThread::started((信号。正如OrcunC所指出的,您需要确保QThread实例的作用域正确。

有关线程的更多信息:http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/

示例:

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");

我将尝试回答为什么您会看到QThread:Destroyed which thread which threaderror。

如果你这样做

void mtMethod () {
 Citizen * c = new Citizen(this);
 QThread thread;
 c->moveToThread(&thread);
 connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
 thread.start();
}

当您退出函数时,线程对象将被销毁,但已启动的线程仍在运行!。Qt警告您应该停止线程或在更大的范围内创建线程对象。(即,将其作为类的成员函数(。类似这样的东西:

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();
}

在调用run之前,我不相信新线程存在。因此构造函数与run((是不同的线程。如果将管理器对象的创建从构造函数转移到run((,会发生什么?我想这将修复第一个错误,如果不是计时器错误的话。

此外,我认为许多人仍在以你的方式构建线程,但你可能想看看这一点。

您需要考虑线程亲和性。这个错误消息并不是在撒谎或疯狂,而是在告诉你到底出了什么问题。

您的问题主要是由于试图将QThread子类化。尽管文档推荐使用QThread,但它并不是使用QThread。有关更多信息和链接,请参阅此问答。

我还没有发现startTimers错误,尽管它可能与第一个错误有关。在任何情况下,您都应该能够修复第一个错误。我在Qt中遇到过几次这个问题,我发现解决这个问题的"最佳"方法是创建一个initialize函数和cleanUp函数。类的所有成员都是在调用run之前初始化为NULL的指针。请注意,"最佳"是在引号中,因为肯定会有不同的意见,但它适用于大多数情况下我。

标题

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();
 };

实施

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*)));
}