Discussion:
Plotting out of a QThread
Thomas Mader
2006-02-09 15:07:04 UTC
Permalink
Hi all,

I'm trying to plot from out of a thread, see code below. Unfortunatly, the program immediately crashes in replot. It helps to remove

QApplication::sendPostedEvents(this, QEvent::LayoutRequest);

and replace

canvas.repaint(canvas.contentsRect());

by

canvas.update(canvas.contentsRect());

But occasionally it crashes despite these changes. Does anybody know the correct way to plot out of a QThread?

I' m using Qt 4.1, the open source Mingw compiler and the newest Qwt 5.0.

Regards
Thomas

....
PaintPltCurves plotThread;
plotThread.mwnd = mainWindw;
....

void TestPltMainWindow::startPlot() {
plotThread.start();
}

void PaintPltCurves::run() {

double* x = mwnd->x;
double* y = mwnd->y;
mwnd->curv1->setRawData(x, y, 0);
mwnd->plotter->d_plot->replot(); **************************crash!!!!!!!
int numData = 500;
double d = 0, delta = 3.14/10;
mwnd->plotter->d_plot->canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, true);
for(int i = 0; i < numData; ++i) {
x[i] = d;
y[i] = sin(d);
d += delta;
if(i > 0) {
mwnd->curv1->setRawData(x, y, i);
mwnd->curv1->draw(i-1, i);
msleep(50);
}
}
}


void QwtPlot::replot()
{
bool doAutoReplot = autoReplot();
setAutoReplot(false);

updateAxes();

/*
Maybe the layout needs to be updated, because of changed
axes labels. We need to process them here before painting
to avoid that scales and canvas get out of sync.
*/
#if QT_VERSION >= 0x040000
// QApplication::sendPostedEvents(this, QEvent::LayoutRequest); *********************************************************
#else
QApplication::sendPostedEvents(this, QEvent::LayoutHint);
#endif

QwtPlotCanvas &canvas = *d_data->canvas;

canvas.invalidatePaintCache();

/*
In case of cached or packed painting the canvas
is repainted completely and doesn't need to be erased.
*/
const bool erase =
!canvas.testPaintAttribute(QwtPlotCanvas::PaintPacked)
&& !canvas.testPaintAttribute(QwtPlotCanvas::PaintCached);

#if QT_VERSION >= 0x040000
const bool noBackgroundMode = canvas.testAttribute(Qt::WA_NoBackground);
if ( !erase && !noBackgroundMode )
canvas.setAttribute(Qt::WA_NoBackground, true);

canvas.update(canvas.contentsRect()); **********************************************************************

if ( !erase && !noBackgroundMode )
canvas.setAttribute(Qt::WA_NoBackground, false);
#else
canvas.repaint(canvas.contentsRect(), erase);
#endif

setAutoReplot(doAutoReplot);
}
Bernhard Lang
2006-02-09 15:36:07 UTC
Permalink
Post by Thomas Mader
I'm trying to plot from out of a thread, see code below. Unfortunatly,
the program immediately crashes in replot. It helps to remove
 
QApplication::sendPostedEvents(this, QEvent::LayoutRequest);
 
and replace
 
canvas.repaint(canvas.contentsRect()); 
 
by
 
canvas.update(canvas.contentsRect()); 
 
But occasionally it crashes despite these changes. Does anybody
know the correct way to plot out of a QThread?
It might have to do with the fact that the GUI has always to run in one
and the same thread. Acting on GUI widgets from different threads is
not safe. An implementation using queued signal/connection could help
in that case. The QwtPlot runs in the GUI thread, the data source
somewhere else. Once data is available and stored at place accessible
for both the data source and the plot the data source sends a (queued)
signal to the plot which will read then the data. You could eventually
use also a mutex construct.
However, I'm not perfectly sure that this is the reason for the crashes
you see...

regards
Bernhard


Bernhard Lang | Physical Chemistry Departement, Sciences II
21, Avenue du Denantou | University of Geneva; 30, Quai Ernest Ansermet
CH-1006 Lausanne, Suisse | CH-1211 Geneva 4, Switzerland
TEL/FAX: +41(0)21 601 3657 | TEL +41(0)22 379-6535, FAX -6518
bernhard.lang at gmx.ch
Uwe Rathmann
2006-02-10 16:16:03 UTC
Permalink
[ crash ... ]
Please build your application in debug mode, start it in your debugger and
post the stack, when it had crashed.

Uwe
Thomas Mader
2006-02-10 19:44:01 UTC
Permalink
Hi,

here are the last lines of the output of the debugger.

gdb: kernel event for pid=4020 tid=ee4 code=CREATE_THREAD_DEBUG_EVENT)
gdb: child_resume.SetThreadContext: thread 4020.0xee4
ContinueDebugEvent (cpid=4020, ctid=3812, DBG_CONTINUE);
gdb: kernel event for pid=4020 tid=3812 code=OUTPUT_DEBUG_STRING_EVENT)

warning: ASSERT failure in QCoreApplication::sendPostedEvents:
"Cannot send posted events for object created in another thread", file kernel\qcoreapplication.cpp, line 877

ContinueDebugEvent (cpid=4020, ctid=3812, DBG_CONTINUE);
gdb: kernel event for pid=4020 tid=3856 code=EXIT_THREAD_DEBUG_EVENT)
ContinueDebugEvent (cpid=4020, ctid=3856, DBG_CONTINUE);
gdb: kernel event for pid=4020 tid=3812 code=EXIT_PROCESS_DEBUG_EVENT)

Program exited with code 01.
ContinueDebugEvent (cpid=4020, ctid=3812, DBG_CONTINUE);
gdb: child_close, inferior_ptid=3856
(gdb) c

It seems not to be allowed to access a QWidget from another thread. Hmm,
at the moment I have no idea how to solve this problem.

Thomas

Loading...