如何修复运行时崩溃 - 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: 无法设置父级,新父级在不同的线程中?的主要内容,如果未能解决你的问题,请参考以下文章

如何修复因 ProGuard/R8 导致的崩溃?

Visual Studio 2015企业在启动,卸载和修复时崩溃

如何修复 QTableWidget setText/setCellWidget 在加载 QSettings 时导致崩溃

如何在接收基于 Flutter 构建的 FCM 推送通知时修复应用程序崩溃

如何让我们淡定解决 程序运行崩溃

Python如何修复由于睡眠功能而导致的Tkinter窗口崩溃