3
votes

I am making a QT application that updates the window based on the information it receives from sockets. This is how I went about doing this:

  1. set up a timer that causes application to check sockets

  2. after new information is recieved (if any), I change context data that is used in painting the widget and call redraw on it

  3. naturally, my code that does the drawing i need is in paint event

However, I have run into a problem. The application isn't stable, and will randomly crash (usually after sending to socket started). Under debug, the stack trace shows it crashes in the depths of QT itself, on the allocation - I presume, judging by the stack - of the another paint event.

How can I prevent this from happening? Maybe, by not calling redraw if the paintng isn't actually done yet?

Code that handles recieving new data; dt.listen() returns number of changed items.

void CommandPanel::update()
{
    //printf("Some drawing is done!\n");
    static int udel = 0;
    udel += 1+dt.listen();
    if ( udel > 40)
    {
        this->repaint(); //!!!
        udel = 0;
    }
}

Code that binds it to timer

//object T that is derived from QWidget is created
QTimer timer;
QObject::connect(&timer, SIGNAL(timeout()), &T, SLOT(update()));
timer.start(1000 / 10);
T.show();

Under debug i reciever a segmentation fault signal when i arrive on the line with '!!!' in comment. Here is a full stack trace.

Thread 3 (Thread 0xb75b9b70 (LWP 9183)): _#0 0x0012e416 in __kernel_vsyscall () No symbol table info available.

_#1 0x00e49834 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib/i386-linux-gnu/libpthread.so.0 No symbol table info available.

_#2 0x01472f0e in ?? () from /usr/lib/i386-linux-gnu/libgthread-2.0.so.0 No symbol table info available.

_#3 0x0114042c in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#4 0x01140f6d in g_async_queue_timed_pop () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#5 0x01198980 in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#6 0x011962df in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#7 0x00e44e99 in start_thread () from /lib/i386-linux-gnu/libpthread.so.0 No symbol table info available.

_#8 0x0105573e in clone () from /lib/i386-linux-gnu/libc.so.6 No symbol table info available.

Thread 2 (Thread 0xb7dbab70 (LWP 9072)): _#0 0x0012e416 in __kernel_vsyscall () No symbol table info available.

_#1 0x01046f76 in poll () from /lib/i386-linux-gnu/libc.so.6 No symbol table info available.

_#2 0x0117d84b in g_poll () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#3 0x0116d1af in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#4 0x0116d92b in g_main_loop_run () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#5 0x0166b304 in ?? () from /usr/lib/i386-linux-gnu/libgio-2.0.so.0 No symbol table info available. _#6 0x011962df in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#7 0x00e44e99 in start_thread () from /lib/i386-linux-gnu/libpthread.so.0 No symbol table info available.

_#8 0x0105573e in clone () from /lib/i386-linux-gnu/libc.so.6 No symbol table info available.

Thread 1 (Thread 0xb7fe4710 (LWP 8938)): _#0 0x00d183f8 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#1 0x00d652f7 in QTimer::timeout() () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#2 0x00d1e3ee in QTimer::timerEvent(QTimerEvent*) () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#3 0x00d17214 in QObject::event(QEvent*) () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#4 0x0025cd24 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib/libQtGui.so.4 No symbol table info available.

_#5 0x002618ce in QApplication::notify(QObject*, QEvent*) () from /usr/lib/libQtGui.so.4 No symbol table info available.

_#6 0x00d020bb in QCoreApplication::notifyInternal(QObject*, QEvent*) () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#7 0x00d321e4 in ?? () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#8 0x00d2ee27 in ?? () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#9 0x0116caa8 in g_main_context_dispatch () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#10 0x0116d270 in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#11 0x0116d524 in g_main_context_iteration () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.

_#12 0x00d2f53c in QEventDispatcherGlib::processEvents(QFlags) () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#13 0x00310775 in ?? () from /usr/lib/libQtGui.so.4 No symbol table info available.

_#14 0x00d01289 in QEventLoop::processEvents(QFlags) () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#15 0x00d01522 in QEventLoop::exec(QFlags) () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#16 0x00d05ecc in QCoreApplication::exec() () from /usr/lib/libQtCore.so.4 No symbol table info available.

_#17 0x0025a8e7 in QApplication::exec() () from /usr/lib/libQtGui.so.4 No symbol table info available.

_#18 0x0804ac19 in main (argc=1, argv=0xbffff8a4) at ../wargui/main.cpp:40

    app = <incomplete type>
    timer = <incomplete type>
    T = {<QLabel> = {<No data fields>}, view = 0x10e33c0, dt = {qflag = 0, channelSockets = {0x8566108 "/tmp/channel1", 0x8567788 "/tmp/channel2", 0x8565298 "/tmp/channel3", 0x8565330 "/tmp/channel4", 0x8567db8 "/tmp/channel5", 0x8567e00 "/tmp/channel6", 0x8567108 "/tmp/channel7"}, mesSources = {0x8567e78, 0x85653a0, 0x85652b0, 0x8565348, 0x8567dd0, 0x85670d8, 0x8567120}, cossock = 33, chansocks = {26, 27, 28, 29, 30, 31, 32}, logLength = {0, 0, 0, 0, 0, 0, 0, 1, 1}, logs = {0x8568620, 0x8568788, 0x85688f0, 0x8568a58, 0x8568bc0, 0x8568d28, 0x8568e90, 0x8568ff8, 0x8569160}, targets = 0x85651e0}}
    pm = <incomplete type>
    r = -1073743880

I must also add the following. If the qt application have started before the messages start arriving on socket, it works without falling. Otherwise, when the messages are already being sent and then the qt application starts, it falls once the first call on update() is made.

2
Perhaps someone else will disagree, but I think this might be too difficult to answer without a minimal bit of code showing what you're doing. Or some more detailed information about the error/stack trace you're seeing.Bart
what do you mean by "... by calling redraw on it"? there is no redraw method on QWidget. and if you're using repaint, well, look closely at the warning in that functions doc.Mat
a) Use QSocketNotifier b) Call update() instead of repaint() (and rename/remove your own update())Frank Osterfeld
The QT documentation says the following: Warning: If you call repaint() in a function which may itself be called from paintEvent(), you may get infinite recursion. The update() function never causes recursion. (doc.trolltech.com/4.7/qwidget.html#repaint)gnud
Overriding the update() and not calling the original, seems like a risky thing to do. Instead of calling repaint() in your update-function, just call the original update().gnud

2 Answers

1
votes

I faced this kind of problems the first time I had overridden an update() method.

Gnud is right calling directly the original update() should fix your problem, if you have something to do/draw/update/paint when a paint event occurs, re-implement paintEvent(QPaintEvent*).

In addition to that, in order to trigger your paint event you can connect a slot to the readyRead() QSocket signal. In this slot you can evaluate bytesAvailable() until a decent amount of data is reached. Then you call an update(). You should also create/reset a one shot timer just in case the data you just received was the last, and the 'decent' amount will never be reached!

1
votes

When you receive a message from the network compare the incoming data with the current data. If it changes then update the data and emit an 'update the gui' event. If that's still too fast then only emit update events at a maximum rate of X per second.

It's good practice not to have your network code know anything about the gui (i.e. Don't call 'repaint'). Instead Emit an "update" event and the gui can handle it as desired. If you change your GUI then your network code doesn't change.