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

Ahm*_*med 7 c++ qt multithreading asynchronous qnetworkaccessmanager

编辑:

我试着做你们在评论中告诉我的事情......:

Citizen * c = new Citizen(this);

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

connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();
Run Code Online (Sandbox Code Playgroud)

这会产生更多错误:

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
Run Code Online (Sandbox Code Playgroud)

我遇到了这个错误的问题......我已经坚持了2天,无法得到解决方案.

标题:

class Citizen : public QThread
{
Q_OBJECT    
    QNetworkAccessManager * manager;

private slots:
    void onReplyFinished(QNetworkReply* net_reply);

public:
    Citizen(QObject * parent);

    void run();
};
Run Code Online (Sandbox Code Playgroud)

执行:

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();
}
Run Code Online (Sandbox Code Playgroud)

当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)
Run Code Online (Sandbox Code Playgroud)

当eLoop.exec()执行时:

QObject::startTimer: timers cannot be started from another thread
Run Code Online (Sandbox Code Playgroud)

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

Citizen * c = new Citizen(this);
c->start();
Run Code Online (Sandbox Code Playgroud)

为什么会这样?怎么解决这个?

Kim*_*meh 10

QObject: Cannot create children for a parent that is in a different thread.
Run Code Online (Sandbox Code Playgroud)

你得到这个是因为你正在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");
Run Code Online (Sandbox Code Playgroud)


O.C*_*.C. 3

我将尝试回答为什么您会看到QThread: Destroyed while thread is still running错误。

如果你这样做

void mtMethod () {

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

 connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
 thread.start();
}
Run Code Online (Sandbox Code Playgroud)

当你退出函数时,线程对象将被销毁,但已经启动的线程仍在运行!。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 Code Online (Sandbox Code Playgroud)

  • 将父级分配给一个对象,然后将其移动到另一个线程是不行的。这个答案是不正确的。@Kim Bowles Sørhus 的答案应该被标记为这样。 (2认同)