Crash using QPainter from secondary thread
-
Hello, I'm trying to draw into a QImage using a QPainter from a secondary thread. As far as I know this should be supported by Qt.
I get a consistent crash (segfault) deep inside the paint engine, possibly sse related. In the code below, it crashes inside the call to painter.drawLine().
I'm running XP using Qt 4.7.3 with mingw and QtCreator 2.1.0I've managed to produce a small sample which exhibits the issue, could anyone take a look and see if I'm doing anything stupid, or even if you can just reproduce it (it doesn't seem to occur on my vista machine).
========== MainWindow.h =========
@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QtGui/QMainWindow>
#include <QThread>
#include <QWidget>
#include <QImage>class Canvas : public QWidget
{
Q_OBJECT
public:
Canvas(QWidget* parent=0);void drawStuff();
protected:
void paintEvent(QPaintEvent *);QImage m_image;
};class RenderThread : public QThread
{
public:
RenderThread(Canvas* canvas) : m_canvas(canvas), m_stopping(false) {}void run();
void stop() { m_stopping = true; }private:
Canvas* m_canvas;
bool m_stopping;
};class MainWindow : public QMainWindow
{
Q_OBJECTpublic:
MainWindow(QWidget *parent = 0);
~MainWindow();private:
RenderThread* m_renderThread;
};#endif // MAINWINDOW_H
=========== MainWindow.cpp ============
#include "MainWindow.h"
#include <QPainter>
#include <QTimer>
#include <QMutex>QMutex g_mutex;
Canvas::Canvas(QWidget *parent)
: QWidget(parent),
m_image(256,256, QImage::Format_ARGB32_Premultiplied)
{
}void Canvas::drawStuff()
{
g_mutex.lock();m_image.fill(0xffffffff);
QPainter painter(&m_image);
QPen pen(QColor(40,90,180,200));
pen.setWidthF(12.0f);
painter.setPen(pen);
painter.drawLine(QPointF(0,0), QPointF(256,256));g_mutex.unlock();
}void Canvas::paintEvent(QPaintEvent *)
{
g_mutex.lock();QPainter p(this);
p.drawImage(0,0, m_image);g_mutex.unlock();
}void RenderThread::run()
{
while(!m_stopping)
{
m_canvas->drawStuff();
msleep(10);
}
}MainWindow::MainWindow(QWidget parent)
: QMainWindow(parent)
{
Canvas canvas = new Canvas(this);
setCentralWidget(canvas);m_renderThread = new RenderThread(canvas);
m_renderThread->start();
}MainWindow::~MainWindow()
{
m_renderThread->stop();
m_renderThread->wait();delete m_renderThread;
}
@EDIT: please use @-tags for code highlighting, thanks. Gerolf
-
-
Well... do you get any messages in the application output about the painter? You could try to do the m_image.fill in the constructor maybe? As soon as you create your canvas, I think it generates a paintEvent() or atleast on the setCentralWidget().. and so maybe drawing the m_image with uninitialized data is the problem.. maybe..
-
Will try to repro..
[Edit: Ubuntu 10.04 Qt SDK 1.1.1 Qt 4.7.4.. works.. no crash.. ]
-
"For info on how to post a bug....":http://developer.qt.nokia.com/wiki/ReportingBugsInQt
-
[quote author="bourbon" date="1308069402"]Does this sound like something that should be reported on the Qt bugtracker? If so, where do I do that?[/quote]
It does to me. Sounds like a regression, and those are generally taken quite seriously. Don't forget to attach your example to reproduce the issue, link to this topic, and add a tag to this topic with the bug id (QTBUG-#####)
-
The first thing that comes in my mind is that you're not end()ing the painting before releasing the lock, thus you're relying on the QPainter dtor (which will end the painting itself).
There's an obvious race condition there, and I'm confident that helgrind would have told you so. Try adding end() there, or switch to QMutexLocker.
-
I have posted the root cause, a small project to reproduce it and a temporary workaround in the Bugtracker for this bug: QTBUG-19886
It is caused by a stack mis-alignment of the newly created thread. It affects the drawing engine which expects 16-byte alignment for the used SSE2 instructions.
It appears to only occur on windows XP. And happens when a QPainter::drawImage is done on a different thread. The stack on the new thread (QThread subclass and started with start()) is NOT 16-bit aligned, and causes a Segmentation Fault on
the MMX instruction PANDN in qdrawhelper_sse2.cpp.The only (dirty) workaround I can think of is to manually push extra bytes on the stack in case it is not aligned to realign the SP to a 16-byte boundary. And this seems to work quite well, no more crashes!