Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I stop an event loop in a QThread?

I have a QThread with a while loop. I need to be able to stop that loop. I tried to emit a signal from the main thread connected to a slot in the QThread that sets a variable to true and thus ends the loop.

The problem is that this connection doesn't work. I read somewhere that connections aren't executed while the slot's thread is in a busy loop. So how do I get around this and tell the thread to stop? It's fine if the loop stops before ending the current iteration.

One way I could perhaps solve this is by having the main process function in the QThread call itself under certain conditions instead of using a while loop, but I figure there has to be a better way?

Here's (simplified) code of what I tried:

processor.h

class Processor : public QObject
{
    Q_OBJECT

    volatile bool processingStopped = false;

public:
    Processor();

public slots:
    /** @brief Process all files in pathList according to provided options. */
    void process();

    /** @brief Save received stop signal and stop processing. */
    void stopProcess();
}

processor.cpp

void Processor::process()
{
    while (!processingStopped) {
        // do some stuff
    }
}

void Processor::stopProcess()
{
    processingStopped = true;
    qDebug("stop processing");
}

mop.h

class Mop : public QObject
{
    Q_OBJECT

    QThread thread;

public:
    Mop();
    ~Mop();

    /** @brief Move a Processor to a QThread, connect signals, and start processing. */
    template<class APP>
    void process(APP &app);

public slots:
    /** @brief Quit the thread and wait(). */
    void quit();

signals:
    void startProcess();
};

mop.tcc

template<class APP>
void Mop::process(APP &app)
{
    Processor *processor = new Processor();
    processor->moveToThread(&thread);

    connect(this, &Mop::startProcess, processor, &Processor::process);
    connect(&thread, &QThread::finished, processor, &Processor::deleteLater);
    connect(&app, &APP::stopProcess, processor, &Processor::stopProcess);

    thread.start();
    emit startProcess();
}

mop.cpp

Mop::~Mop()
{
    quit();
}

void Mop::quit()
{
    thread.quit();
    thread.wait();
}

mainwindow.h

class MainWindow : public QMainWindow
{
    Q_OBJECT

    Mop         mop;

    void doProcess(const QStringList &paths);
    void closeEvent(QCloseEvent *event) override;

signals:
    void stopProcess();
}

mainwindow.cpp

void MainWindow::closeEvent(QCloseEvent *event)
{
    event->ignore();

    if (QMessageBox::Yes == QMessageBox::question(this, "Close Confirmation", "Are you sure you want to quit?", QMessageBox::Yes | QMessageBox::No))
    {
        // Emit the signal to stop processing. The current loop will finish and then the thread will quit.
        emit stopProcess();
        event->accept();
    }
}

// This is executed when a button is pressed
void MainWindow::doProcess(const QStringList &paths)
{
    mop.process();
}
like image 391
bur Avatar asked Dec 22 '25 22:12

bur


1 Answers

Problem

The issue is that you moved an object to a thread that is owned by the object itself. This is the root cause of your problems and it leads to a deadlock.

When you move an object to a thread, invoking deleteLater schedules the deletion of the object on that thread. Since the object owns the thread, its destructor attempts to delete the thread as well. This means the object's destructor tries to join the thread.

However, a QThread can only be joined when its event loop is empty — that is, after the object has been deleted. This creates a deadlock: the object’s destruction waits for the thread to finish, while the thread waits for the object to be destroyed.

How to Fix This

An object that is moved to a thread should never own that thread. Instead, the thread should exist independently, alongside the Mop instance. This separation will eliminate the deadlock.

like image 126
Marek R Avatar answered Dec 24 '25 12:12

Marek R



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!