简体   繁体   中英

Qt multi-thread with GUI

I cannot produce a very simple example to getting start with Qt multi-thread. I read a lot of posts and tutorials but still it doesn't work.

Goal

Have a background worker independent from the GUI. Oh, wow...

What I did

A simple example:

  • create the Engine class
  • that shows a QMainWindow
  • and starts a QTimer that prints a number

But if you left-click the title bar of the GUI , keeping pressed the mouse button (ie on the minimize button) the counter will stop ! Even if it was created in a non-GUI environment and it was moved in another thread!

Why?

main.cpp

#include "engine.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Engine e;

    return a.exec();
}

engine.h

#ifndef ENGINE_H
#define ENGINE_H

#include <QObject>
#include <QThread>
#include <QTimer>

#include "mainwindow.h"

class Engine : public QObject
{
    Q_OBJECT

public:
    explicit Engine(QObject *parent = 0);

private:
    MainWindow mainWindow;
    QThread *thread;
    QTimer *timer;

private slots:
    void foo();

};

#endif // ENGINE_H

engine.c

#include "engine.h"
#include <QDebug>

Engine::Engine(QObject *parent) : QObject(parent)
{

    thread = new QThread(this);
    timer = new QTimer();
    timer->setInterval(100);
    connect(timer, &QTimer::timeout, this, &Engine::foo);
    connect(thread, &QThread::started, timer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
    timer->moveToThread(thread);
    thread->start();

    mainWindow.show();
}

void Engine::foo()
{
    static int i;
    qDebug() << ++i;
}

The QMainWindow contains no code.

Basically, Qt has one thread dealing with the GUI (typically the main thread). Any objects specific to this thread will be blocked by GUI work. You need to keep the GUI outside of your interacting partners.

To be more specific, your Engine object resides in the GUI/main thread. Even while your timer is sent to a worker thread, its signals are dispatched to the slot foo() in the main thread.

You need to de-mangle Engine and the main window such that Engine can reside in its own thread and process signals while the GUI is blocking.

Looks like you moved QTimer instance to your custom thread, but you didnt move Engine instance to this thread, therefore, foo slot of Engine class will be executed in main thread.

I can suggest you using additional helping QObject-derived class instance within Engine class and move it to your new thread in Engine constructor.

With following changes solution works fine even with minimize button pressed (I've commented places where i added or changed anything. Also added new QObject-derived class EngineWorker ):

Engine.h

#ifndef ENGINE_H
#define ENGINE_H

#include <QObject>
#include <QThread>
#include <QTimer>

#include "mainwindow.h"
#include "engineworker.h"

class Engine : public QObject
{
    Q_OBJECT

public:
    explicit Engine(QObject *parent = 0);

private:
    MainWindow mainWindow;
    QThread *thread;
    QTimer *timer;

    //additional QObject-derived class
    EngineWorker *worker;

private slots:
    void foo();

};

#endif // ENGINE_H

Engine.cpp

#include "engine.h"
#include <QDebug>


Engine::Engine(QObject *parent) : QObject(parent)
{
      thread = new QThread(this);
      timer = new QTimer();

      //Creating instance of Engine worker
      worker = new EngineWorker();

      timer->setInterval(100);

      //Connecting Engine worker' foo slot to timer
      connect(timer, &QTimer::timeout, worker, &EngineWorker::foo);
      connect(thread, &QThread::started, timer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
      timer->moveToThread(thread);
      //Moving worker to custom thread
      worker->moveToThread(thread);

      thread->start();

      mainWindow.show();
}

void Engine::foo()
{
    static int i;
    qDebug() << ++i;
}

EngineWorker.h

#ifndef ENGINEWORKER_H
#define ENGINEWORKER_H

#include <QObject>
#include <QDebug>

class EngineWorker : public QObject
{
    Q_OBJECT
public:
    explicit EngineWorker(QObject *parent = 0);

signals:

public slots:
    void foo();
};

#endif // ENGINEWORKER_H

EngineWorker.cpp

#include "engineworker.h"

EngineWorker::EngineWorker(QObject *parent) : QObject(parent)
{

}

//foo slot of EngineWorker class
void EngineWorker::foo()
{
    static int j;
    qDebug() <<"Worker: "<< ++j;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM