melanholly
melanholly

Reputation: 772

Qt Interface freeze on background task

I have an entertaining problem to solve. I use Qt 5 for one of my projects for reading information on the network. I read modbus devices and stuff, but the real problem comes when the network isn't available.

The interface freezes and I can't interact with it. The network stuff is done in a separate thread or that is what I think. Here is some code example:

class TwidoDevice : public QObject
{
    Q_OBJECT
public:
    explicit TwidoDevice
........ And some useful code

The use of the (main interface) class in Window.cpp is:

L1Thread = new QThread();
L1Thread->start();
L1TWD = new TwidoDevice(L1TWD_settings,
                        L1TWD_Name,
                        PercentRegisters,
                        TotalsRegisters,
                        db, 1);
L1TWD->moveToThread(L1Thread);
connect(this, SIGNAL(startReading()), L1TWD, SLOT(startFired()), Qt::DirectConnection);

In this code startFired() start reading the devices on the network.

In some other function in Window.cpp:

emit startReading()

When this code is executed the interface freezes even though I've moved the L1TWD object to QThread.

When I try to debug it using the built-in debugger in QtCreator, I can't seem to understand whether the object has been moved or not and why the interface is frozen during the network call.

Has any one encountered the same problem and what is the way to solve this?

Thank you for spending time reading my question!

Upvotes: 1

Views: 1165

Answers (2)

MatthiasB
MatthiasB

Reputation: 1759

You are using a Qt::DirectConnection for your connection, which means the slot is called immediately, i.e on the same thread as the signal was fired. You can have a look at the documentation for ConnectionType. What you want to use is probably Qt::QueuedConnection, which executes the slot in the thread of the receiving object.

The best way though, as lpapp pointed out, is to let Qt decide what is best, and simply use Qt::AutoConnection, which is the default. It will use a QueuedConnection if signaling and receiving threads are different, and DirectConnection otherwise.

Upvotes: 4

László Papp
László Papp

Reputation: 53225

This is the main problem:

connect(this, SIGNAL(startReading()), L1TWD, SLOT(startFired()), Qt::DirectConnection);

You are connecting the receiver and sender in different threads with direct connection, which will block the UI. Given that your slot execution gets stuck, this is expected. You have at least two issues here to solve.

  • Use the default connection which will not block across threads, just inside the same thread. So, you would be writing something like this:

connect(this, SIGNAL(startReading()), L1TWD, SLOT(startFired()));

  • Secondly, you could make sure that your thread does not get stuck when there is some "network" problem.

For debugging purposes, please print out the current thread when having this kind of threading issues using the following methods:

[static] QThread * QThread::​currentThread()

Returns a pointer to a QThread which manages the currently executing thread.

and this:

[static] Qt::HANDLE QThread::​currentThreadId()

Returns the thread handle of the currently executing thread.

Warning: The handle returned by this function is used for internal purposes and should not be used in any application code.

Warning: On Windows, the returned value is a pseudo-handle for the current thread. It can't be used for numerical comparison. i.e., this function returns the DWORD (Windows-Thread ID) returned by the Win32 function getCurrentThreadId(), not the HANDLE (Windows-Thread HANDLE) returned by the Win32 function getCurrentThread().

Upvotes: 4

Related Questions