Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    QGraphicsPathItem(parent) constructor crashes (SIGSEGV) possible 5.3 bug!

    General and Desktop
    3
    8
    2003
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • L
      lexxxel last edited by

      Hallo,

      if I create an path object (class Path : public QObject, public QGraphicsPathItem) in an other std::thread then his parent item (class Anchor : public QObject, public QGraphicsPixmapItem), it crashes.
      The funny thing is, that it doesn't crashes if the QMainWindow that holds the QGraphicScene has no parent. If it's parent is a QTabWidget it crashes.

      EDIT:: I found, it only crashes in Qt 5.3.0 MinGW 32bit (prebuild) not in 5.2.1 MinGW 32bit (prebuild) -> could be a bug
      Anchor.cpp
      @void Anchor::addDistanceValue(double distanceValue) {
      mutex.lock();
      bool stillWorking = isWorking;
      mutex.unlock();
      if(!stillWorking){
      mutex.lock();
      isWorking = true;
      mutex.unlock();
      if (wallCheckerThread.joinable()){
      //QTime timeStamp = QTime::currentTime();
      wallCheckerThread.join();
      //qDebug() << "wait to join anker: " << id << "in " << timeStamp.msecsTo(QTime::currentTime()) << "ms";
      }

          wallCheckerThread = std::thread([&](double distanceValue){
      
              QTime timeStamp = QTime::currentTime();
      
              classMutex.lock();
              mutex.lock();
              Path* item = new Path(distanceValue * 100, this); // <<--- here is the problem, the this
              mutex.unlock();
              //item->setPos(pos());
              item->setVisible(false);
              //scene()->addItem(item);
              classMutex.unlock();
      
      
              checkAdditionalPathLossChanges(distanceValue, item);
      
              qDebug() << "Anker " << getId() << ": " << timeStamp.msecsTo(QTime::currentTime()) << "ms";
      
              QPen pen;
              pen.setColor(0x8888ff);
              item->setPen(pen);
              item->setFlags(0);
              item->setAcceptedMouseButtons(Qt::NoButton);
      
              distanceVector.push_back(distanceValue);
      
              ellipses.append(item);
      
              if (distanceVector.length() > 1){
                  distanceVector.pop_front();
      
                  classMutex.lock();
                  delete ellipses.first();
                  //scene()->removeItem(ellipses.first());
                  classMutex.unlock();
      
                  if (!ellipses.isEmpty())
                      ellipses.pop_front();
              }
              item->setVisible(true);
              mutex.lock();
              isWorking = false;
              mutex.unlock();
          }, distanceValue);
      }else{
          qDebug() << "skipped anker " << id;
      }
      

      }@

      path.h
      @#include <QGraphicsItem>
      #include <QObject>
      #include <QGraphicsSceneMouseEvent>

      class Path : public QObject, public QGraphicsPathItem
      {
      Q_OBJECT
      Q_INTERFACES(QGraphicsItem)

      public:
      explicit Path(qreal radius, QGraphicsItem *parent = 0):
      QGraphicsPathItem(parent) // << here it crashes (path.h 15)
      {
      myPath = new QPainterPath();
      myPath->addEllipse(QRectF(-radius,-radius,radius * 2, radius * 2));
      setPath(*myPath);
      setZValue(1);
      }

      .....

      protected:
      ....
      QPainterPath *myPath;
      };
      @

      working if its used this way:

      @

      int main(int argc, char *argv[])
      {
      QApplication app(argc, argv);
      RadarWidget radarWidget; // << has its own window
      radarWidget.show();
      SerialWidget mainWindow;
      mainWindow.show();
      QObject::connect(&mainWindow, SIGNAL(newDistanceData(int, double)), &radarWidget, SLOT(addNodeDistance(int, double)));
      radarWidget.setSettingsProvider(mainWindow.getSettingsProvider());
      return app.exec();

      ////////////////////////

      just as additional info:
      the signal is passed to the right anchor

      void RadarGraphicsView::addNodeDistance(int id, double distance){

      ...
      
      Anchor::classMutex.lock();
      Anchor *newAnchor = new Anchor(id);
      this->scene()->addItem(newAnchor);
      Anchor::classMutex.unlock();
      double x = settings->getSetting(id, "x");
      double y = settings->getSetting(id, "y");
      newAnchor->setPos(x,y);
      newAnchor->addDistanceValue(distance);
      anchors.append(newAnchor);
      

      }
      ////////////////////////////////////////
      }@

      it isnt working this way:

      @SerialWidget::SerialWidget(QWidget *parent) :
      QMainWindow(parent),
      ui(new Ui::SerialWidget)
      {
      ui->setupUi(this);

      ....

      // if the qmainwindow is a chiild of this object ----------------------|
      QObject::connect(this, SIGNAL(newDistanceData(int, double)), ui->sWRadar, SLOT(addNodeDistance(int, double))); // <<--- the radar is a child of the mainwindow
      ui->sWRadar->setSettingsProvider(deviceSettings);
      

      }@

      the debugger says:

      SIGSEGV
      Segmantation fault

      stack:
      @
      0 ?? 0x1d2bf51c
      1 QCoreApplicationPrivate::checkReceiverThread 513 0x6b929693
      2 QApplication::notify 2791 0x91eb4ba
      3 QCoreApplication::notifyInternal 935 0x6b929f96
      4 QCoreApplication::sendEvent 237 0x9536429
      5 QGraphicsScene::setFocus 2969 0x94a835a
      6 QGraphicsScenePrivate::setActivePanelHelper 743 0x94a1c63
      7 QGraphicsScene::setActivePanel 5644 0x94b180c
      8 QGraphicsItem::setActive 3188 0x94813fc
      9 QGraphicsItemPrivate::setParentItemHelper 1222 0x947b90a
      10 QGraphicsItem::setParentItem 1685 0x947ce1b
      11 QGraphicsItem::QGraphicsItem 1399 0x947c412
      12 QAbstractGraphicsShapeItem::QAbstractGraphicsShapeItem 8076 0x948c56a
      13 QGraphicsPathItem::QGraphicsPathItem 8217 0x948c8c9
      14 Path::Path path.h 15 0x43010a
      15 Anchor::__lambda2::operator() anchor.cpp 364 0x40f3cb
      16 std::_Bind_simpleAnchor::addDistanceValue(double)::__lambda2(double)::_M_invoke<0u>(std::_Index_tuple<0u>) functional 1732 0x41184f
      17 std::_Bind_simpleAnchor::addDistanceValue(double)::__lambda2(double)::operator()(void) functional 1720 0x41173c
      18 std::thread::_Impl<std::_Bind_simpleAnchor::addDistanceValue(double)::__lambda2(double) >::_M_run(void) thread 115 0x4116a4

      1 Reply Last reply Reply Quote 0
      • SGaist
        SGaist Lifetime Qt Champion last edited by

        Hi and welcome to devnet,

        Can you reproduce this with a minimal compilable example ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply Reply Quote 0
        • L
          lexxxel last edited by

          this should do the job. press the button twice. it works if u compile it with release config. it breaks under debug
          I can't totally reproduce my error but that this program shows an similar problem
          mainwindow.h
          @#ifndef MAINWINDOW_H
          #define MAINWINDOW_H

          #include <QMainWindow>
          #include <thread>
          #include <QGraphicsPathItem>

          namespace Ui {
          class MainWindow;
          }

          class MainWindow : public QMainWindow
          {
          Q_OBJECT

          public:
          explicit MainWindow(QWidget *parent = 0);
          ~MainWindow();

          private:
          Ui::MainWindow *ui;

          bool init;
          std::thread otherThread;
          QGraphicsPathItem *itemParent;
          

          private slots:
          void on_pushButton_clicked();
          };

          #endif // MAINWINDOW_H
          @

          @#include "mainwindow.h"
          #include "ui_mainwindow.h"
          #include <QGraphicsPixmapItem>
          #include <QGraphicsView>

          MainWindow::MainWindow(QWidget *parent) :
          QMainWindow(parent),
          ui(new Ui::MainWindow)
          {
          ui->setupUi(this);

          QGraphicsScene *scene = new QGraphicsScene(this);
          scene->setItemIndexMethod(QGraphicsScene::NoIndex);
          ui->graphicsView->setScene(scene);
          scene->setSceneRect(0, 0, 100, 100);
          
          //scene->setSceneRect(scene->sceneRect() + QMarginsF(100,100,100,100));
          //scene->setSceneRect(-width/2, hight/2, width/2, hight/2);
          ui->graphicsView->setCacheMode(QGraphicsView::CacheBackground);
          ui->graphicsView->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
          ui->graphicsView->setRenderHint(QPainter::Antialiasing);
          ui->graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
          ui->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
          ui->graphicsView->setUpdatesEnabled(true);
          
          init = false;
          

          }

          MainWindow::~MainWindow()
          {
          if(otherThread.joinable()) otherThread.join();
          delete ui;
          }

          void MainWindow::on_pushButton_clicked()
          {
          if(init == false){
          init = true;
          QPainterPath path;
          path.addEllipse(QRectF(-10,-10,10 * 2, 10 * 2));
          itemParent = new QGraphicsPathItem(path);
          ui->graphicsView->scene()->addItem(itemParent);

          }else{
              if(otherThread.joinable()){
                  otherThread.join();
              }
              otherThread = std::thread([&](){
                  QPainterPath path;
                  path.addRect(-10,-10,20,20);
                  QGraphicsPathItem *child = new QGraphicsPathItem(path, itemParent);
              });
          }
          

          }
          @

          1 Reply Last reply Reply Quote 0
          • A
            Asperamanca last edited by

            As far as I know, QGraphicsItems are not meant to be used in any thread other than the main thread.

            1 Reply Last reply Reply Quote 0
            • L
              lexxxel last edited by

              I think so, too. But one: I need it that way, two: it works in release and at least: to check collisions it should be unimportant which thread access them.

              1 Reply Last reply Reply Quote 0
              • A
                Asperamanca last edited by

                If it works in release, that can be a happy coincidence having to do with the timing you have on the very machine you are testing on. It could easily break again as soon as you test it elsewhere.

                And why do you "need it that way"? Has someone defined that "collision detection must run in a separate thread"? Or are you rather talking about a performance requirement that might be met using other ways?

                1 Reply Last reply Reply Quote 0
                • L
                  lexxxel last edited by

                  Yes it's a performance problem. I have hundreds of parent items and all of them get every second a new child item. the average calculation time is 90ms per child, which means it has to be parallel. If I push the creation of the child item to the main thread. the collideWith() crashes in the subthread.
                  About the timming thing. I stopped the main thread right after the creation of the sub thread with .join() and so both version should create the child at the exact same state and it still crashed only in debug.

                  1 Reply Last reply Reply Quote 0
                  • A
                    Asperamanca last edited by

                    From the sources you have posted, I do not really understand what you are trying to achieve. So you create about 100 child items per second. What is the "calculation time"? What do you do in that calculation? Why does the calculation take 90 ms? Could you optimize it so the main thread can easily handle the load?
                    Does this calculation actually require the GraphicsScene? Or could you do the calculation purely with QPainterPath and QRectF objects (in which case a different thread would be no problem anymore).

                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post