1

i have a worker thread which i try to stop through a button. i sometimes get the following error:

Fatal: QThread: Destroyed while thread is still running

Here is my code. By pushing the disconnect button a signal is emitted to stop the thread's while loop.

if (ui->connectButton->text() == "Connect") {
    mUDPThread = new QThread;
    mUDPWorker = new  UDPThread(ui->HostTextEdit->toPlainText(), ui->portTextEdit->toPlainText().toInt());
    mUDPWorker->moveToThread(mUDPThread);
    connect(mUDPThread, SIGNAL(started()), mUDPWorker, SLOT(process()));
    connect(mUDPWorker, SIGNAL(finished()), mUDPThread, SLOT(quit()));
    connect(mUDPWorker, SIGNAL(finished()), mUDPWorker, SLOT(deleteLater()));
    connect(mUDPWorker, SIGNAL(finished()), mUDPThread, SLOT(deleteLater()));
    connect(this, SIGNAL(onExitThread()), mUDPWorker, SLOT(onExitThread()));
    connect(this, SIGNAL(onDataIncome(QString)), mUDPWorker, SLOT(onDataIncome(QString)));
    mUDPThread->start();
    ui->connectButton->setText("Disconnect");
} else if (ui->connectButton->text() == "Disconnect") {
    emit onExitThread();
    ui->connectButton->setText("Connect");
}

the worker Thread:

void UDPThread::process() {
    while (isRunning) {
    QCoreApplication::processEvents();
      ...
    }
    emit finished();
}
void UDPThread::onExitThread() {
    qDebug() << "onExitThread" << isRunning;
    isRunning = false;
}
momor10
  • 478
  • 3
  • 11

2 Answers2

2

while (isRunning)

You are blocking the thread right there, its event loop cannot spin in order to receive signals, it can only send signals to other threads with spinning event loops.

You need to make your worker non-blocking, split the work in cycles, in between the event loop gets to spin and receive signals. In pseudocode:

if (isRunning) {
  doWorkCycle();
  scheduleNextWorkCycle();
} else emit finished();

There is an example you can look at here.

dtech
  • 47,916
  • 17
  • 112
  • 190
  • sorry, i call processEvents() and emit finished() of course. i updated the question – momor10 Oct 26 '17 at 13:51
  • @momosxp I don't think that helps, as the thread is blocked it will not receive any events you can force to process. Even if it could work, having to call `processEvents()` manually is an indication of bad design. – dtech Oct 26 '17 at 13:54
  • thanks for your help. I tried to implement it according to the link using invokemethod. Like that it works without using processEvents but it still sometimes crashes with the same error message. – momor10 Oct 26 '17 at 15:03
  • I don't know implementation details on how it works with Qt, however the example I linked to has you covered in any case. There is some extra verbosity, having to split the work so it can be done in discrete steps, but if you do much of that, you can implement an abstract class to reuse and simply implement initialization and work steps. – dtech Oct 26 '17 at 15:17
0

Solved it. The error was within the connect commands:

connect(mUDPWorker, SIGNAL(finished()), mUDPThread, SLOT(deleteLater()));

to

connect(mUDPThread, SIGNAL(finished()), mUDPThread, SLOT(deleteLater()));

result:

connect(mUDPThread, SIGNAL(started()), mUDPWorker, SLOT(process()));
connect(mUDPWorker, SIGNAL(finished()), mUDPThread, SLOT(quit()));
connect(mUDPWorker, SIGNAL(finished()), mUDPWorker, SLOT(deleteLater()));
connect(mUDPThread, SIGNAL(finished()), mUDPThread, SLOT(deleteLater()));
connect(this, SIGNAL(onExitThread()), mUDPWorker, SLOT(onExitThread()));
connect(this, SIGNAL(onDataIncome(QString)), mUDPWorker, SLOT(onDataIncome(QString)));
momor10
  • 478
  • 3
  • 11