QThread and Slots



  • I am working with a small application which has a QMainWindow and a class which inherits QThread. A class instance is created by the QMainWindow. Slots and signals are used to communicate between the main window and the class. However, the main window gui is not responsive while the signal/slot communication is active. The thread performs lengthy calculations. I have written a small program which shows the problem, and it is shown below as a single file. Clicking on the window close box has no effect until the signal/slot flow is stopped.

    ========== ThreadTest.pro ==========
    
    QT       += core gui
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = ThreadTest
    TEMPLATE = app
    
    
    SOURCES +=  main.cpp\
                mainwindow.cpp \
                actionthread.cpp
    
    HEADERS +=  includes.h\
                mainwindow.h \
                actionthread.h
    
    ========== Includes.h ==========
    
    #ifndef INCLUDES_H
    #define INCLUDES_H
    
    #include <QApplication>
    #include <QDebug>
    #include <QMainWindow>
    #include <QMutex>
    #include <QMutexLocker>
    #include <QThread>
    #include <QTime>
    
    #endif // INCLUDES_H
    
    ========== actionthread.h ==========
    
    #ifndef ACTIONTHREAD_H
    #define ACTIONTHREAD_H
    
    #ifndef INCLUDES_H
    #include "includes.h"
    #endif
    
    static const int ON  = 1;
    static const int OFF = 0;
    
    class ActionThread : public QThread
    {
        Q_OBJECT
    
    public:
        ActionThread(QObject* parent = 0);
        ~ActionThread();
    
        void run();
    
        int sw;
        QTime myTime;
    
    public slots:
        void calculateInt(int num);
    
    signals:
        void resultInt(int result);
    };
    
    #endif // ACTIONTHREAD_H
    
    ========== actionthread.cpp ==========
    
    #include "actionthread.h"
    
    
    //---------- class ActionThread ----------
    
    ActionThread::ActionThread(QObject* parent) : QThread(parent)
    {
        qDebug()<<"CONSTRUCTOR   ActionThread";
    
        sw = ON;
        myTime.start();
    }
    
    //---------- Destructor ----------
    
    ActionThread::~ActionThread(){
    
        qDebug()<<"DESTRUCTOR   ActionThread";
    }
    
    //---------- run ----------
    
    void ActionThread::run(){
    
        qDebug()<<"  run";
    }
    
    //---------- SLOT calculateInt ----------
    
    void ActionThread::calculateInt(int num){
    
        int endTime = num & 0x000000FF;                 // 0..255
        int result = 0;
    
        myTime.restart();
        bool stay = true;
        while (stay){
    
            result++;
    
            if (myTime.elapsed() > endTime){
                stay = false;
            }//if
    
            if (sw == OFF){
                stay = false;
            }//if
        }//while
    
        if (sw == ON){
            emit resultInt(result);
        }//if
        else{
            qDebug()<<"sw == OFF";
        }
    }
    
    ========== MainWindow.h ==========
    
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #ifndef ACTIONTHREAD_H
    #include "actionthread.h"
    #endif
    
    #ifndef INCLUDES_H
    #include "includes.h"
    #endif
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
        void doInit();
    
        ActionThread* myThread;
        QMutex mutex;
    
        int counter = 0;
    
    
    
    public slots:
        void handleResult(int result);
    
    signals:
        void calculateThisInt(int num);
    };
    
    #endif // MAINWINDOW_H
    
    ========== MainWindow.cpp ==========
    
    #include "mainwindow.h"
    
    //---------- class MainWindow ----------
    
    MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
    {
        qDebug()<<"CONSTRUCTOR   MainWindow";
    
        myThread = new ActionThread(this);
        myThread->start();
    }
    
    //---------- Destructor ----------
    
    MainWindow::~MainWindow()
    {
        qDebug()<<"DESTRUCTOR   MainWindow";
    
        mutex.lock();
        myThread->sw = OFF;
        mutex.unlock();
    }
    
    //---------- doInit ----------
    
    void MainWindow::doInit(){
    
        qDebug()<<"   doInit";
    
        connect(myThread, &ActionThread::resultInt, this, &MainWindow::handleResult);
        connect(this, SIGNAL(calculateThisInt(int)), myThread, SLOT(calculateInt(int)));
    
        emit calculateThisInt(qrand());
    }
    
    //---------- SLOT handleResult ----------
    
    void MainWindow::handleResult(int result){
    
        qDebug()<<"result "<<result;
    
        if (++counter < 25)
        emit calculateThisInt(qrand());
    
        update();
    }
    
    ========== main.cpp ==========
    
    #include "mainwindow.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.setAttribute(Qt::WA_QuitOnClose);
        w.show();
        w.doInit();
    
        return a.exec();
    }
    

  • Moderators

    This question was asked maaaany times. Long story short, the problem is here:

    myThread = new ActionThread(this);
    myThread->start();
    

    QObjects have a thread affinity. In other words they "live" in a thread and their slots are run in the thread they live in. QThread object executes its run() method in another thread, but the object itself lives in the main thread (or whatever thread the new ActionThread was called in), so the connection you made is between objects in same thread and your slot will be called in main thread and block the emitting signal call.

    The suggested way to use threads is to use a worker object and move it to the other thread.
    Please refer to the docs for detailed description and example.



  • @Chris-Kawa
    Thank You!! When all else fails, read the instructions! The following code works. Again, Thanks!

    
    ========== ThreadTest.pro ==========
    
    #-------------------------------------------------
    #
    # Project created by QtCreator 2016-02-05T12:17:41
    #
    #-------------------------------------------------
    
    QT       += core gui
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = ThreadTest
    TEMPLATE = app
    
    
    SOURCES +=  main.cpp\
                mainwindow.cpp \
        actionobject.cpp
    
    HEADERS +=  includes.h\
                mainwindow.h \
        actionobject.h
    
    ========== includes.h ==========
    
    #ifndef INCLUDES_H
    #define INCLUDES_H
    
    #include <QApplication>
    #include <QDebug>
    #include <QMainWindow>
    #include <QMutex>
    #include <QMutexLocker>
    #include <QThread>
    #include <QTime>
    
    #endif // INCLUDES_H
    
    ========== actionobject.h ==========
    
    #ifndef ACTIONOBJECT_H
    #define ACTIONOBJECT_H
    
    #ifndef INCLUDES_H
    #include "includes.h"
    #endif
    
    class ActionObject : public QThread
    {
        Q_OBJECT
    
    public:
        ActionObject(QObject* parent = 0);
        ~ActionObject();
    
        QTime myTime;
    
    public slots:
        void calculateInt(int num);
    
    signals:
        void resultInt(int result);
    };
    
    #endif // ACTIONOBJECT_H
    
    ========== actionobject.cpp ==========
    
    #include "actionobject.h"
    
    //---------- class ActionObject ----------
    
    ActionObject::ActionObject(QObject* parent) : QThread(parent)
    {
        qDebug()<<"CONSTRUCTOR   ActionObject";
    
        myTime.start();
    }
    
    //---------- Destructor ----------
    
    ActionObject::~ActionObject(){
    
        qDebug()<<"DESTRUCTOR   ActionObject";
    }
    
    //---------- SLOT calculateInt ----------
    
    void ActionObject::calculateInt(int num){
    
        int endTime = num & 0x000000FF;                 // 0..255
        int result = 0;
    
        myTime.restart();
        bool stay = true;
        while (stay){
    
            result++;
    
            if (myTime.elapsed() > endTime){
                stay = false;
            }//if
    
        }//while
    
        emit resultInt(result);
    }
    
    ========== mainwindow.h ==========
    
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #ifndef ACTIONOBJECT_H
    #include "actionobject.h"
    #endif
    
    #ifndef INCLUDES_H
    #include "includes.h"
    #endif
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
        QThread myThread;
    
    public:
        MainWindow(QWidget *parent = 0){
            qDebug()<<"CONSTRUCTOR   MainWindow";
            ActionObject* myObject = new ActionObject();
            myObject->moveToThread(&myThread);
            connect(&myThread, &QThread::finished, myObject, &QObject::deleteLater);
            connect(myObject, &ActionObject::resultInt, this, &MainWindow::handleResult);
            connect(this, &MainWindow::calculateThisInt, myObject, &ActionObject::calculateInt);
            myThread.start();
        }
    
        ~MainWindow(){
            qDebug()<<"DESTRUCTOR   MainWindow";
            myThread.quit();
            myThread.wait();
        }
    
        void doInit();
    
        int counter = 0;
    
    public slots:
        void handleResult(int result);
    
    signals:
        void calculateThisInt(int num);
    };
    
    #endif // MAINWINDOW_H
    
    ========== mainwindow.cpp ==========
    
    #include "mainwindow.h"
    
    //---------- doInit ----------
    
    void MainWindow::doInit(){
    
        qDebug()<<"   doInit";
    
        emit calculateThisInt(qrand());
    }
    
    //---------- SLOT handleResult ----------
    
    void MainWindow::handleResult(int result){
    
        qDebug()<<"result "<<result;
    
        if (++counter < 30)
        emit calculateThisInt(qrand());
    
        update();
    }
    
    ========== main.cpp ==========
    
    #include "mainwindow.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.setAttribute(Qt::WA_QuitOnClose);
        w.show();
        w.doInit();
    
        return a.exec();
    }
    
    
    

  • Moderators

    Just a note - your ActionObject should not inherit QThread now. You're not using it to start a thread. That's what you've got myThread object for. Inheriting from plain QObject will be fine.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.