修改
我试着做你们在评论中告诉我的事情......:
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_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
我遇到了这个错误的问题......我已经坚持了2天了,无法得到解决方案。
标题
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-&gt; 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();
为什么会这样?怎么解决这个问题?
答案 0 :(得分:10)
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");
答案 1 :(得分:3)
我将尝试回答为什么你看到 QThread:在线程仍在运行时被破坏错误。
如果你这样做
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();
}
答案 2 :(得分:1)
在调用run之前,我不相信新线程存在。所以构造函数是一个与run()不同的线程。如果将manager对象的构建从构造函数移动到run()会发生什么?我想这将解决第一个错误,如果不是定时器错误也是如此。
此外,我认为很多人仍然按照您的方式构建线程,但您可能想查看this。
答案 3 :(得分:1)
您需要考虑thread affinity。该错误消息不是说谎或疯狂,它告诉你完全错误。
答案 4 :(得分:1)
您的问题主要是由于尝试将QThread子类化。即使文档推荐它,它也不是使用QThread的最佳方式。有关更多信息和链接,请参阅this question and answer。
答案 5 :(得分:1)
我还没有弄清楚startTimers错误,尽管它可能与第一个错误有关。无论如何,您应该能够修复第一个错误。我在Qt中遇到过这个问题几次,我发现这是解决它的“最佳”方法是创建一个初始化函数和一个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*)));
}