1
votes

In my code a worker thread emits a signal to gui thread. Signal and Slot are connected via Qt::BlockingQueuedConnection.

When during thecloseEvent application is trying to stop the worker thread and only then finishes the event.

It calls the function of worker thread:

void stop() {
  _isFinished = true;
  wait();
}

The worker thread in its turn checks _isFinished condition and if it is not set up then emit the signal.

Imaging the following situation

The worker            Gui Thread 
=================     =================
if (!_isFinished)     -----------------
-----------------     _isFinished = true;
-----------------     wait();
emit mySignal();      -----------------

Evidently, both threads would be locked - deadlock.

If I add a mutex then you can find another deadlock situation. When the worker locks the mutex and the gui thread would be blocked. As a result the emitted signal will lock the worker.

How can I deal with this?

2
Is there some particular reason why you use BlockingQueuedConnection rather than QueuedConnection? - Jeremy Friesner
Yes, it is important, because the slot which is connected to the signal needs to release memory objects, in other case the memory overflow occurs. - user14416

2 Answers

1
votes

This is how I see the situation.

In your main thread you do not need to wait for worker to quit. Instead your closeEvent should look like this:

if (workerThread->isRunning())
{
    workerThread->stop();
    event->ignore();
}

To make this work, you also need to close main window, when worker thread finishes:

connect(workerThread, SIGNAL(finished()), SLOT(close()));

Finally, all manipulations with _isFinished (and all other variables in worker thread) should occur in worker thread. You can achieve it with a simple trick:

WorkerThread.h

public:
    void stop();

protected slots:
    void p_stop();

protected:
    QMutex mutex;

WorkerThread.cpp

void WorkerThread::stop()
{
    staticMetaObject.invokeMethod(this, "p_stop", Qt::QueuedConnection);
}

void WorkerThread::p_stop();
{
    QMutexLocker locker(&mutex);
    _isFinished = true;
}

This way you can avoid deadlocks.

0
votes

In the gui thread you can use QEventLoop for wait. Look like this:

void stop() {
    QEventLoop eventloop;
    connect(&theWorkerThread, &QThread::finished, &eventloop, QEventLoop::quit);
    _isFinished = true;
    eventloop.exe();
}