Qt在构建移动到线程的QObject时将“this”作为父级传递

时间:2012-02-28 21:40:43

标签: c++ multithreading qt qthread

阅读完文档后,我发现了这个:

  

必须始终在创建父项的线程中创建QObject的子项。除其他外,这意味着你永远不应该将QThread对象(this)作为在线程中创建的对象的父对象传递(因为QThread对象本身是在另一个线程中创建的。)< / p>

我不确定这意味着什么,所以我做了一些例子,并想知道这将适用于哪里。

一个。

class MyThread : public QThread {
    MyThread(QObject *parent = 0) : QThread(parent) {
        QNetworkAccessManager *test = new QNetworkAccessManager (this); 
       // here I assume that this child(test) will have the main thread (creator of MyThread)
       // as it's parent and it will go horrible wrong. 
    }
    ....
}

B中。

class MyThread : public QThread {
    QNetworkAccessManager *test;
    MyThread(QObject *parent = 0) : QThread(parent) {}

    void run {
       test = new QNetworkAccessManager(this); 
       // will the main thread be the parent here aswell?
       // if I remove "this" this will work since its created in the thread (not the main thread)
    }
    ....
}
哎呀,但是怎么样?

请注意,这些对象将像这样创建和启动:

MyThread *fakeThread = new MyThread; // should I or should I not pass "this" as a parent here?
QThread realThread;

fakeThread->moveToThread(&realThread);

realThread.start();
QMetaObject::invokeMethod(fakeThread, "start", Qt::QueuedConnection);

下进行。

class MyThread : public QObject {
    MyThread(QObject *parent = 0) : QObject(parent) {
        QNetworkAccessManager *test = new QNetworkAccessManager(this); 
       // I assume this constructor still will be create the the QNAM as a child to 
       // the main thread and it will not work
    }

    void start {
        ....
    }
}

d。

class MyThread : public QObject {
    QNetworkAccessManager *test;
    MyThread(QObject *parent = 0) : QObject(parent) {}

    void start {
       test = new QNetworkAccessManager(this); 
       // What about now? 
    }
    ....
}

我真的想要实现选项D,以便我可以轻松删除对象。例如,如果我想读取大量文件,并且我希望在线程死亡时取消分配所有文件。

此外,QThread派生版本与将QObject移动到线程的版本之间的主要区别是什么?在使用Qthread时,文档总是说明做和不做,但我对此有点不确定。

我现在最大的问题是我有一个派生自QObject的类,它将被移动到一个线程。在该对象中,我创建了另一个对象。该对象包含QNetworkAccessManagerQFile。我在哪里将“this”作为父母传递,或者在线程中我不应该这样做?请解释。

此时,在堆上创建属于对象(RestHandler,即一个线程)的对象(让我们称之为uploader)。这是因为大多数函数使用它,如果它是在堆栈的头文件中创建的,它的父元素将是主线程。将在堆栈上创建RestHandler a QNetworkAccessManager中的内容。

编辑:

在阅读答案后,我尝试在堆栈上创建restHandlerQNetworkAccessManager,然后移动它们。输出如下:

  

Resthandeler构造函数:restHandler在线程中创建   QThread(0x22d5e8),线程QThread中的accessManager(0x22d5e8)   当前位置QThread(0x22d5e8)

然后,当我尝试移动resthandler时,我收到以下警告:

QObject::moveToThread: Current thread (0x1fbf0e0) is not the object's thread (0x22d5e8).
Cannot move to target thread (0x1fbf0e0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0x42a477c), parent's thread is QThread(0x22d5e8), current thread is QThread(0x4196f98)

我猜有没有办法解决这个问题?该程序似乎运行并且正确的线程中调用了插槽,但它崩溃之前似乎是一个时间问题。

1 个答案:

答案 0 :(得分:3)

来自Threads and QObjects documentation

  

事件驱动对象只能在单个线程中使用。   具体而言,这适用于计时器机制和网络   模块。例如,您无法启动计时器或连接套接字   不是对象线程的线程。

对您而言,这意味着您的QNetworkAccessManager需要位于您将连接套接字等的线程中。它不能是您的MyThread对象的子项,如果它在您的初始化构造函数,在线程启动后需要移动MyThread

  

您必须确保删除线程中创建的所有对象   在删除QThread之前。这可以通过创建来轻松完成   run()实现中堆栈上的对象。

你有没有理由在堆上分配QNetworkAccessManager?你可以让它成为一个普通成员(在堆栈上)吗?

来自QNetworkAccessManager docs:

  

网络访问API围绕一个QNetworkAccessManager构建   对象,它包含常用的配置和设置   要求它发送。它包含代理和缓存配置,如   以及与此类问题相关的信号,以及可以回复的信号   用于监视网络操作的进度。 <强>一   QNetworkAccessManager对于整个Qt应用程序应该足够了。

这告诉我,您可能想要重新考虑使用此类对象拥有多个线程的设计决策,以及您是否可以遵循预期的使用模式。您仍然可以通过threadsafe signal/slot connections将许多工作线程连接到属于主线程的QNetworkAccessManager的单个实例。