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 anchorvoid 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 faultstack:
@
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 -
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_OBJECTpublic:
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.
-
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).