如何修复运行时崩溃 - QObject::setParent: 无法设置父级,新父级在不同的线程中?
Posted
技术标签:
【中文标题】如何修复运行时崩溃 - QObject::setParent: 无法设置父级,新父级在不同的线程中?【英文标题】:How to fix the runtime crash - QObject::setParent: Cannot set parent, new parent is in a different thread? 【发布时间】:2014-04-17 09:15:07 【问题描述】:我编写了一个 QT - webkit 应用程序。当我的 pSeudo 驱动程序获取字符“l”时,此应用程序会触发回调。但是,应用程序在回调期间崩溃 - 它说 - QObject::setParent: 无法设置父级,新父级在不同的线程中。我不知道要解决这个问题,我尝试做 moveToThread,但它没有帮助。请在这里帮助我。
#include <QtGui/QApplication>
#include <QApplication>
#include <QDebug>
#include <QWebFrame>
#include <QWebPage>
#include <QWebView>
#include <QThread>
#include <unistd.h>
#include <fcntl.h>
class DemoThread;
class MyjavascriptOperations : public QObject
Q_OBJECT
public:
QWebView *view;
DemoThread *m_pDemoThread;
MyJavaScriptOperations();
void firecb();
bool slot_installed;
signals:
void alert_script_signal();
public slots:
void JS_ADDED();
void loadFinished(bool);
private:
;
class DemoThread : public QThread
public:
DemoThread( MyJavaScriptOperations *pJavascriptOp);
protected:
void run();
private :
MyJavaScriptOperations *m_pJavascriptOp;
;
DemoThread::DemoThread(MyJavaScriptOperations *pJavascriptOp):m_pJavascriptOp(pJavascriptOp)
void DemoThread:: run()
int filedesc = open("/dev/pSeudoDrv", O_RDONLY);
if(filedesc < 0)
qDebug()<<"Couldn't open Driver.";
unsigned char buff;
while(1)
read(filedesc,&buff, 1);
qDebug()<<"The code received is "<< buff;
if ( (m_pJavascriptOp->slot_installed == true) && (buff == 166))
m_pJavascriptOp->firecb();
qDebug()<<"Running Thread.";
sleep(6);
void MyJavaScriptOperations::JS_ADDED()
qDebug()<<__PRETTY_FUNCTION__;
view->page()->mainFrame()->addToJavaScriptWindowObject("myoperations", this);
void MyJavaScriptOperations::loadFinished(bool oper)
qDebug()<<__PRETTY_FUNCTION__<< oper;
slot_installed = true;
// firecb();
void MyJavaScriptOperations::firecb()
qDebug()<<__PRETTY_FUNCTION__;
view->page()->mainFrame()->evaluateJavaScript("JavaScript_function()");
MyJavaScriptOperations::MyJavaScriptOperations()
qDebug()<<__PRETTY_FUNCTION__;
view = new QWebView();
view->resize(400, 500);
connect(view->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(JS_ADDED()));
connect(view, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
view->load(QUrl("./index.html"));
view->show();
int main(int argc, char *argv[])
QApplication a(argc, argv);
MyJavaScriptOperations *jvs = new MyJavaScriptOperations;
DemoThread *thread = new DemoThread(jvs);
jvs->moveToThread(thread);
thread->start();
return a.exec();
#include "main.moc"
这是我得到的崩溃错误 -
./QT_DEMO
MyJavaScriptOperations::MyJavaScriptOperations()
loaded the Generic plugin
The code received is 156
Running Thread.
The code received is 166
void MyJavaScriptOperations::firecb()
QObject::setParent: Cannot set parent, new parent is in a different thread
【问题讨论】:
你正在做一些非常危险的事情。您正在从非 gui 线程执行 GUI 工作。您的view
对象应该存在于 GUI 线程中,但您正在从不同的线程访问它的函数,而这些函数不是线程安全的函数。您的线程中也没有运行事件循环,因此永远不会通过信号调用您的插槽。即使您确实运行了一个事件循环,您的 while(1)
循环也会阻止它。
read() 使其成为事件循环。
read()
是否在呼叫QThread::exec()
?
我对事件循环的理解是会等待事件发生,直到任何事件发生才会阻塞。因此,我正在使用 read(),它将阻塞线程,直到读取检索到任何东西。我已经修复了崩溃。请看我的解决方案。请告诉我,如果有设计问题。顺便说一句,我的角色驱动程序在这里 - ***.com/questions/23133981/…。该功能有效,但问题是当我删除字符驱动程序时。我的系统崩溃了。
并且必须在某处输入事件循环。它不会自己神奇地做到这一点。当您调用QApplication::exec
时,即进入事件循环。当您调用进入事件循环的QThread::exec
时。如果你想在你的线程中使用槽,你必须告诉你的线程进入事件循环。
【参考方案1】:
互联网上关于如何在 Qt 中制作多线程应用程序的文章很少。最好的解释可以在这里找到:
http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/
您还可以阅读其他文章:
https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
【讨论】:
我实际上建议仅阅读其他文章,因为它们清楚地概述了为什么“最佳解释”(即 debao.me 的第一个链接)实际上是错误的。 .(请注意,qt-project.org/wiki/QThreads_general_usage 是从 Maya Posch 的博客中复制粘贴...)【参考方案2】:好吧,我找到了解决问题的方法。请告诉我,我是否使解决方案复杂化。 我正在使用信号和插槽。线程将发出信号,其他类的插槽将向 Qtwebkit - javascript 函数发出回调。这样对吗? 因为,我建议使用事件循环 - exec()。
#include <QtGui/QApplication>
#include <QApplication>
#include <QDebug>
#include <QWebFrame>
#include <QWebPage>
#include <QWebView>
#include <QThread>
/** for reading my driver **/
#include <unistd.h>
#include <fcntl.h>
class DemoThread;
class MyJavaScriptOperations : public QObject
Q_OBJECT
public:
QWebView *view;
DemoThread *m_pDemoThread;
MyJavaScriptOperations();
void firecb();
bool slot_installed;
signals:
void alert_script_signal();
public slots:
void JsAdded();
void alertReceived();
void loadFinished(bool);
private:
;
class DemoThread : public QThread
Q_OBJECT
private:
MyJavaScriptOperations *m_pJavascriptOp;
public:
DemoThread( MyJavaScriptOperations *pJavascriptOp);
protected:
void run();
signals:
void alertSendSignal();
;
DemoThread::DemoThread(MyJavaScriptOperations *pJavascriptOp):m_pJavascriptOp(pJavascriptOp)
connect(this, SIGNAL(alertSendSignal()), m_pJavascriptOp, SLOT(alertReceived()));
void DemoThread:: run()
int filedesc = open("/dev/pSeudoDrv", O_RDONLY);
if(filedesc < 0)
qDebug()<<"Couldn't open Driver.";
unsigned char buff;
while(1)
if( 1 != read(filedesc,&buff, 1))
qDebug()<<"Read Invalid Data";
qDebug()<<"The code received is "<< buff;
/** In my laptop, the 166 means the character 'l' **/
if ( (m_pJavascriptOp->slot_installed == true) && (buff == 166))
emit alertSendSignal();
qDebug()<<"Running Thread.";
void MyJavaScriptOperations::JsAdded()
qDebug()<<__PRETTY_FUNCTION__;
view->page()->mainFrame()->addToJavaScriptWindowObject("myoperations", this);
void MyJavaScriptOperations::loadFinished(bool oper)
qDebug()<<__PRETTY_FUNCTION__<< oper;
slot_installed = true;
void MyJavaScriptOperations::alertReceived()
qDebug()<<"Sending Firecallback now";
firecb();
void MyJavaScriptOperations::firecb()
qDebug()<<__PRETTY_FUNCTION__;
view->page()->mainFrame()->evaluateJavaScript("JavaScript_function()");
MyJavaScriptOperations::MyJavaScriptOperations()
qDebug()<<__PRETTY_FUNCTION__;
view = new QWebView();
view->resize(400, 500);
connect(view->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(JsAdded()));
connect(view, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
view->load(QUrl("./index.html"));
view->show();
int main(int argc, char *argv[])
QApplication a(argc, argv);
MyJavaScriptOperations *jvs = new MyJavaScriptOperations;
DemoThread *thread = new DemoThread(jvs);
thread->start();
return a.exec();
#include "main.moc"
【讨论】:
最后的代码看起来更好。 QThread 它经常用于保护 GUI 免受 IO 阻塞操作。但最好将 Qt 也用于 IO 操作,请参阅 QIODevice、QFile、QDataStream、QTextStream 类。一些 QIODevice 派生类 (QTcpSocket) 是事件驱动的,因此不需要使用 QThread。以上是关于如何修复运行时崩溃 - QObject::setParent: 无法设置父级,新父级在不同的线程中?的主要内容,如果未能解决你的问题,请参考以下文章
Visual Studio 2015企业在启动,卸载和修复时崩溃
如何修复 QTableWidget setText/setCellWidget 在加载 QSettings 时导致崩溃