QCustomPlot Discussion and Comments

Program crash after calling replot()Return to overview

Hi. I´m really desperate with one problem. I have application that recieves a value from another application every second. I would like to do some math with that and then display result in two graphs. In one step I always update one of the two graph.

The following function is calling in the independent threat running while the connection between the two applications insist and recieves value and use them in some way:

void mainWnd::useDataFromPipe(double val) {
    if(val<=*DOF) {
        //FSO spracovanie
        lastRecievedFSO->saveValue(val);
        FSOvectorX->append(FSOcounter); FSOvectorY->append(1.0); FSOcounter=FSOcounter+1.0;
        if(!firstDataFSO()) {
           //rutinny algoritmus - bezi pre kazdy krok zapisu vacsi ako 1
            if(val>maximumRecievedFSO->loadValue()) maximumRecievedFSO->saveValue(val);
            else if(val<minimumRecievedFSO->loadValue()) minimumRecievedFSO->saveValue(val);
        }
        else {
           //prve zapisovane data
           maximumRecievedFSO->saveValue(val);
           minimumRecievedFSO->saveValue(val);
        }
        numberOfRecievedValuesFSO->saveValue(numberOfRecievedValuesFSO->loadValue()+1.0);
    }
    else {
        //RF spracovanie
        lastRecievedRF->saveValue(val);
        RFvectorX->append(RFcounter); RFvectorY->append(1.0); RFcounter=RFcounter+1.0;
        if(!firstDataRF()) {
           //rutinny algoritmus - bezi pre kazdy krok zapisu vacsi ako 1
            if(val>maximumRecievedRF->loadValue()) maximumRecievedRF->saveValue(val);
            else if(val<minimumRecievedRF->loadValue()) minimumRecievedRF->saveValue(val);
        }
        else {
           //prve zapisovane data
           maximumRecievedRF->saveValue(val);
           minimumRecievedRF->saveValue(val);
        }
        numberOfRecievedValuesRF->saveValue(numberOfRecievedValuesRF->loadValue()+1.0);
    }
    FSOGraph->graph(0)->clearData();
    RFGraph->graph(0)->clearData();
    FSOGraph->graph(0)->setData(*FSOvectorX, *FSOvectorY);
    RFGraph->graph(0)->setData(*RFvectorX, *RFvectorY);
    //FSOGraph->replot();
    //RFGraph->replot();
}

If I remove FSOGraph->replot(); and RFGraph->replot(); everything runs ok, I can see all QLabels being updated by right values and everything seems to run good. But if I uncomment replot() functions the application will crash after one or two cycles but I really don´t know why. I´m using Qt 4.8.1 and mingw compiler. Can you help me please?

Do you call setData() and replot() on the same QCustomPlot instance from different theads? This can cause crashes if the setData is called in the middle of the replot. The methods are not marked thread-safe! Make sure to use mutexes to prevent simultaneous calls from different threads on the same QCustomPlot object.

yes...Thank you. I have changed an algorithm a little bit, and I´ve added mutex. But now I´ve noticed another problem. The application will run in real time but also a very long time obtaining data. To test whether everything runs fine I set (only for test reasons) obtaining data each 10ms (in normal state it will be 1 second). After some time I noticed that some of QLabels stopped updating and sometimes happen that also graphs stopped plotting although another widgets continue. Sometimes the application crash. Is there any possibility that the time 10ms is too short time for updating graphs or another Qt widgets?

No, 10ms data acquisition rate is no problem if you take some points into consideration for high performance visualization applications.

The problem is more likely the replot time. And locking/unlocking mutexes also shouldn't be underestimated. You probably don't want to completely lock down your second thread when replotting, but create a data buffer in the first thread which can be continuously filled by the second thread. You also have to decouple data acquisition from replot. For example, put the replot() in a timer slot which gets called maybe at 30 FPS or even less when you plot high data densities. In the background you can then add data at 10ms without problem, from within the same thread (that's why the buffer in the first thread is necessary, to not block the data acquisition thread while replotting). Note that at very high data densities (Say 500,000 points and more) you will notice slowdown of your whole application on today's systems. That's just their limit. If you need more than that, you should consider making a specialized plottable for your purpose, which then for example does pixmap buffering and throws away much of the flexibility of the general-purpose QCPGraph.

However the easiest solution is always to simply not show all data at the same time, but let it scroll out of the view during acquisition.

in fact the graphs will be only graphs with the first point stable and the and second point will be moving according to data recieved. So I changed all plotting to the (I think) the simplest variant that I´m adding to graph only vectors with 2 values - coordinates of 2 points that are connected then with line.

I have the code below that´s running each second:

signalEmitter = new QTimer(this);
connect(signalEmitter, SIGNAL(timeout()), this, SLOT(updateGraphsSlot()));
signalEmitter->start(1000);
.
.
.
void mainWnd::updateGraphsSlot(void) {
    if(*updateGraphsSlotControl) {
    *updateGraphsSlotControl = false;
    updateGraphMutex->lock();
    FSOGraph->graph(0)->setData(*FSOvectorXshort, *FSOvectorYshort);
    //FSOGraph->graph(0)->addData(0.0, 1.0);
    FSOGraph->replot();

    RFGraph->graph(0)->setData(*RFvectorXshort, *RFvectorYshort);
    //RFGraph->graph(0)->addData(0.0, 1.0);
    RFGraph->replot();
    updateGraphMutex->unlock();
    *updateGraphsSlotControl = true;
    }
}

the values I´m saving in another thread like this:

void mainWnd::useDataFromPipe(double val) {
 	...
        updateGraphMutex->lock();
        RFvectorXshort->replace(1, RFcounter);
        updateGraphMutex->unlock();
	...
}

mainWnd::useDataFromPipe() function should run each second. So is this wrong approach and should I prefer buffer instead as you said?

If I'm not mistaken, the RFvectorXshort/RFvectorYshort are vectors that play the role of a buffer, right? If that is so, then this implements the method I've described before. To further improve the design, you could consider designing the buffer in a way that it can be read at any time and written to at any time. For example, this can be done with a circular buffer. You will need monitoring algorithms (with atomic ints denoting the current read/write position) to make sure the writing position never overtakes the reading position. If that happens you need to temporarily lock with a mutex and let the reading catch up (and possibly increase the circular buffer size).