PDA

View Full Version : Longstanding problem with crashing, 'pure virtual function call'



MattPhillips
9th August 2014, 16:19
Hi,

I'm just plotting a couple of curves on a canvas. This problem happens when the number of samples in the curves is very high >100,000--and not when its more like 1000. Basically the program will draw for a little while, then crash with the pure virtual function call error message (which I think just indicates corrupted memory) and output like this:


QWidget::repaint: Recursive repaint detected
QPainter::begin: A paint device can only be painted by one painter at a time.
QPainter::translate: Painter not active
QPainter::begin: A paint device can only be painted by one painter at a time.
QPainter::save: Painter not active
QPainter::setClipRect: Painter not active
QPainter::save: Painter not active
QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::restore: Unbalanced save/restore
QPainter::save: Painter not active
QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::save: Painter not active
QPainter::setPen: Painter not active
QPainter::pen: Painter not active
QPainter::restore: Unbalanced save/restore
QPainter::restore: Unbalanced save/restore
QPainter::save: Painter not active
...

My replot is activated by a timer, so it could be that replot is being called before the widget is finished drawing from the previous call. So how do I tell the QwtPlot to wait, or to skip this round? With some of these curves I really lose important information if I simply subsample, so that's not a good option for me.

Matt

Cah
11th August 2014, 05:09
I am not sure why you would want to call replot() periodically via a timer. Did you try setAutoReplot()

MattPhillips
11th August 2014, 14:07
I do this because I do the calculations behind the data display in a worker thread, and call replot() when they are done. I use a Qt::BlockingQueuedConnection for this and have an assert() statement which guarantees that replot() is only ever getting called from the main thread.

I did try setAutoReplot(), and commented out my call to replot(), but the program crashed immediately, segfaulting in QwtPlot::drawItems. I also got this warning: "QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread".

Cah
11th August 2014, 18:48
Is the calculation time dependent...
Are you doing some sort of sampling...
How about qwtsamplethread...

MattPhillips
11th August 2014, 22:46
What is QwtSampleThread? I couldn't find that anywhere. I don't know what you mean by 'time-dependent', of course, the calculation takes some time. The timer doesn't fire until after it's complete though, so 100ms is a lower bound on the interval between repaints.

Cah
11th August 2014, 23:56
What is QwtSampleThread
My mistake ... It's QwtSamplingThread and not QwtSampleThread


I don't know what you mean by 'time-dependent', of course, the calculation takes some time
I had a look at my post and do understand the confusion. What I wanted to know is if time is the independent variable (time vs dependent_variable)

I am still no clear why you need the help of a separate thread for calculation.

MattPhillips
12th August 2014, 13:59
Yes, time is generally the independent variable, but what the data represent is immaterial, or have I still not understood you? Basically the program runs a numerical simulation, and the evolution of the state variables is displayed as they evolve.

I use a separate thread for calculation for the usual reason--I don't want the gui blocked while the calculations are taking place. The user needs to be able to adjust parameters, etc. as the simulation progresses.

Uwe
12th August 2014, 19:21
When I'm implementing similar situations I usually use a timer in the GUI thread, that periodically checks a flag + calling replot when it has been set + clears the flag. The worker thread does nothing beside its job + setting the flag, when it has delivered something new.

Uwe

MattPhillips
12th August 2014, 22:08
Hi Uwe,

Is the problem that I create and attach QwtPlotItems to QwtPlots within a worker thread? Do you do this? My intuition had been that calling replot from a worker thread could fail but just making the objects could be done anywhere. Otherwise, what you're saying sounds just like what I do, except that in your case the timer is in the main thread whereas in mine it's in the worker thread, which shouldn't make any difference.

Cah
13th August 2014, 00:46
I believe signal emission is always thread-safe.


class CalculationThread : public QThread
{
Q_OBJECT

public:
CalculationThread(QObject *parent = 0);
~CalculationThread();

void calculation(CalculationData & data);
void run();

signals:
void dataChanged();
void error(const QString &message);

private:
...
CalculationData m_data
QMutex mutex;
...
};


void CalculationThread::calculation(CalculationData & data)
{
QMutexLocker locker(&mutex);
m_data = data;
if (!isRunning())
start();
...
}


void CalculationThread::run()
{
mutex.lock();

...
//do time consuming calculations
...

if(/*data changed*/)
emit dataChanged();
mutex.unlock();
}


class Plot: public QwtPlot
{
...

private slots:
dataChangedCalc()

}

Plot::dataChangedCalc()
{
...
// create and attach QwtPlotItems to QwtPlots
...
this->replot()

}


connect(&thread, SIGNAL(dataChanged()), this, SLOT(dataChangedCalc()));

Note: the this pointer is a pointer to a Plot



Is the problem that I create and attach QwtPlotItems to QwtPlots within a worker thread?
I assuming that you are creating and attaching many plotItems (that's your motivation for putting this activity in the worker thread)
QObject and subclasses thereof are not thread safe. QwtPlot is asubclas of QObject.

MattPhillips
13th August 2014, 16:40
Cah,

Yes, this is what it looks like I will have to try. My version of the '// create and attach QwtPlotItems to QwtPlots' part of 'dataChangedCalc' is in the worker thread; only the replot is in the mean thread. My hope is to gain some insight in advance as to whether this really should make the critical difference--see my previous post--but not knowing any other reasonable possibility I'll probably just try this in any case. Maybe you're right and it's the non-thread-safety of QwtPlot that's getting me; I only have one worker thread on the QwtPlot in question but maybe OS-generated calls to replot are causing the problem. I'll post my results in this thread when I have them.

Uwe
14th August 2014, 09:08
Attaching/detaching items from a different thread is definitely not thread safe !

To make it safe you would have at least to introduce a mutex to avoid that attaching/detaching and iterating over the items in the replot operation do conflict.

For guarding the replot it is probably best to overload QwtPlot::replot(), where you do the mutex stuff before calling the base class.

Uwe