【问题标题】:How to fix the runtime crash - QObject::setParent: Cannot set parent, new parent is in a different thread?如何修复运行时崩溃 - QObject::setParent: 无法设置父级,新父级在不同的线程中?
【发布时间】: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(),它将阻塞线程,直到读取检索到任何东西。我已经修复了崩溃。请看我的解决方案。请告诉我,如果有设计问题。顺便说一句,我的角色驱动程序在这里 - stackoverflow.com/questions/23133981/…。该功能有效,但问题是当我删除字符驱动程序时。我的系统崩溃了。
  • 并且必须在某处输入事件循环。它不会自己神奇地做到这一点。当您调用QApplication::exec 时,即进入事件循环。当您调用进入事件循环的QThread::exec 时。如果你想在你的线程中使用槽,你必须告诉你的线程进入事件循环。

标签: c++ qt qthread


【解决方案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。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-17
  • 2016-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-09
相关资源
最近更新 更多