PDA

View Full Version : Qt 'loses' connections...?



sebastian.f
17th July 2009, 08:35
Hello,

I have a very Very tricky bug in my Qt App.

In short, a Qt application on CE loads a DLL which exports a set of functions to create a QWidget.

The Qt application receives commands via a TCP socket from a desktop and does stuff accordingly like show widgets, send events etc.

The program works 100% fine.. about 25% of the time.

Sometimes when I load the program something goes wrong which has two symptoms:
1. The TCP socket stops recieveing data (or at the least doesnt emit any events)
2. The Qt widget created by the DLL doesn't redraw when the user interacts with it.

However, its not just a case of these two objects not working:
1. Though the TCP socket doesn't emit the readyRead() signal it is still capable of consistently sending sensible data to the desktop and does so as expected.
2. The created Qt Widget doesnt redraw but I can interact with it; I can change its value at it behaves as expected - I just can't see what its doing!

Another widget (QPushButton) created outside the DLL works fine.

Placing breakpoints in the DLL confirms that paintEvent() is never getting called when the problem occurs.

I have an application wide event filter and the behaviour of this indicates that the application is indeed processing events fine and not hanging or getting stuck in a loop or anything like that - eventHandler() triggers for all events, BUT it Doesn't trigger when the desktop pc sends data to the TCP socket, this is what leads me to believe it never receives it in the first place.

I can think of no reason for this behaviour; it appears to occur at random as soon as the QWidget is loaded - restart the app and somtimes it will work and the other times it will break.

Is there any way the paintEvent() or readyRead() signals could have been disconnected?

wysota
17th July 2009, 08:46
Does the DLL use threads?

sebastian.f
17th July 2009, 08:57
Hello wysota,

I don't create any threads myself, the only related command I have is:
moveToThread( QApplication::instance()->thread() );
In the constructor to my main Widget in the DLL as I use a timer.

Also an update: I've been comparing the call stack between my widget from the DLL and the working widget on the form.
As far as I can tell the deviation occurs in QWidget::event called by the notifyHelper() method of QApplicationPrivate (QtGui dll).

Within this method on clicks for the working widget and my widget both times it correctly identifies the events as mouse presses and calls the mousePressEvent() method (which I assume is overridden by both QAbstractButton and my widget).

When I click the working button I can follow the stack down to a successful repaint() call, but when I click my widget I cannot enter the mousePressEvent() method with the debugger, which I assume is because this is inside the loaded DLL, however I do have an update() call inside my mousePressEvent() override in my DLL and as I said before the app seems to get back to the main event loop fine so it just isn't getting called for some reason.

It does sound like a problem with threads given that the TCP socket suddenly goes out of sync, is there something I can try to test this?

EDIT: New update - On my QWidget I have a QPushButton, this time when it broke I guessed where it would be on the screen and pressed it; when I hit it, I followed the stack through and found that the program does reach the repaint() call that all QAbstractButtons() do, so my program is calling repaint, but it just isn't doing it.

wysota
17th July 2009, 09:12
I don't create any threads myself, the only related command I have is:
moveToThread( QApplication::instance()->thread() );
In the constructor to my main Widget in the DLL as I use a timer.
Why do you need that call?

sebastian.f
17th July 2009, 09:15
I create a pointer to a timer as a member of my class, when it is instantiated the timer object is created within the constructor and the timer is turned on and off from methods within my widget, if I dont have that call I get errors about how QTimers cannot be controlled from different threads.

PS. I have that call in both my main app and the DLL, I thought I might accidentally be getting the instance of QCoreApplication from one and QApplication in the other but I checked and they are both QApplication, and so both should be in the same thread, right?

wysota
17th July 2009, 10:26
I create a pointer to a timer as a member of my class, when it is instantiated the timer object is created within the constructor and the timer is turned on and off from methods within my widget, if I dont have that call I get errors about how QTimers cannot be controlled from different threads.
So you are using threads in the dll. You need to find it - it is causing your application to malfunction.


PS. I have that call in both my main app and the DLL, I thought I might accidentally be getting the instance of QCoreApplication from one and QApplication in the other but I checked and they are both QApplication, and so both should be in the same thread, right?

An application may only have one application object.

sebastian.f
17th July 2009, 10:53
I tried removing the call to moveToThread() in the DLL and it made no difference, of course now I think about it since the QWidget is a child of the object in my Qt app, that I had already called moveToThread() on I shouldn't need to call it again.

The timer is the only object I could think of that makes use of threads and I removed the call to make the timer from the DLL but the problem still occurs.

I have since worked my way up into the qt_internal_proc() function which is provided as the message handler for windows created for Qt's internal use.
Ive noted that when the problem occurs this stops recieving the WM_USER messages (for the socket), though it still receives timer events.

I will modify the DLL so that it is capable of creating its widget without a parent and see if that helps.
I wouldn't suppose there is an easy way of finding all the threads in a Qt application?

Update: Modifying the DLL to remove the relationship between the objects in the DLL and the main app did not work; the widget failed to display and the TCP problem occurred again.

Update: I've had a look at the threads window in the debugger and there are four threads, mainWCRTsetup, one the name of which is just a memory location (always the same one), which I assume is for the timer owing to its 'Time Critical' priority, and two with the name of the start() method of QThreadPrivate which are created when I make a TCP connection.

There doesnt appear to be any change in the makeup of these between the program working and not.
If I debug the DLL I see the same thing.