Search code examples
c++multithreadingqtqthreadqtcore

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!


Solution

  • 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().