Unsolved 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(); }
-
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 thenew 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(); }
-
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.