阅读完文档后,我发现了这个:
必须始终在创建父项的线程中创建
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
的类,它将被移动到一个线程。在该对象中,我创建了另一个对象。该对象包含QNetworkAccessManager
和QFile
。我在哪里将“this”作为父母传递,或者在线程中我不应该这样做?请解释。
此时,在堆上创建属于对象(RestHandler
,即一个线程)的对象(让我们称之为uploader
)。这是因为大多数函数使用它,如果它是在堆栈的头文件中创建的,它的父元素将是主线程。将在堆栈上创建RestHandler
a QNetworkAccessManager
中的内容。
编辑:
在阅读答案后,我尝试在堆栈上创建restHandler
和QNetworkAccessManager
,然后移动它们。输出如下:
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)
我猜有没有办法解决这个问题?该程序似乎运行并且正确的线程中调用了插槽,但它崩溃之前似乎是一个时间问题。
答案 0 :(得分:3)
来自Threads and QObjects documentation:
事件驱动对象只能在单个线程中使用。 具体而言,这适用于计时器机制和网络 模块。例如,您无法启动计时器或连接套接字 不是对象线程的线程。
对您而言,这意味着您的QNetworkAccessManager
需要位于您将连接套接字等的线程中。它不能是您的MyThread
对象的子项,如果它在您的初始化构造函数,在线程启动后需要移动MyThread
。
您必须确保删除线程中创建的所有对象 在删除QThread之前。这可以通过创建来轻松完成 run()实现中堆栈上的对象。
你有没有理由在堆上分配QNetworkAccessManager
?你可以让它成为一个普通成员(在堆栈上)吗?
网络访问API围绕一个QNetworkAccessManager构建 对象,它包含常用的配置和设置 要求它发送。它包含代理和缓存配置,如 以及与此类问题相关的信号,以及可以回复的信号 用于监视网络操作的进度。 <强>一 QNetworkAccessManager对于整个Qt应用程序应该足够了。
这告诉我,您可能想要重新考虑使用此类对象拥有多个线程的设计决策,以及您是否可以遵循预期的使用模式。您仍然可以通过threadsafe signal/slot connections将许多工作线程连接到属于主线程的QNetworkAccessManager
的单个实例。