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



  • 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


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Can you reproduce this with a minimal compilable example ?



  • 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);
        });
    }
    

    }
    @



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



  • 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.



  • 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?



  • 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.



  • 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).


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.