I have 3 classes, A, B and C;
Here is class A: A.h
#ifndef A_H
#define A_H
#include <QObject>
class A : public QObject {
Q_OBJECT
public:
A();
void doWork();
signals:
void ready(QString str, QVector<double> v);
};
#endif // A_H
A.cpp
#include "A.h"
#include <QVector>
A::A() {
}
void A::doWork() {
QVector<double> x;
for(int i = 0 ; i < 10; i++) {
x.push_back(i);
}
emit ready("A ready", x);
}
B and C are exactly the same. Only the loop in doWork in class B is until 10000 and in C until 100000000 (8 zeroes).
Just for the test of using QThreads I created 3 QLabel:
QLabel* lbl_a;
QLabel* lbl_b;
QLabel* lbl_c;
This is my MainWindow code:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
#include "A.h"
#include "B.h"
#include "C.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void handlerA(QString str, QVector<double> v);
void handlerB(QString str, QVector<double> v);
void handlerC(QString str, QVector<double> v);
private slots:
void on_btn_start_clicked();
private:
Ui::MainWindow *ui;
A* a;
B* b;
C* c;
QThread thread_a;
QThread thread_b;
QThread thread_c;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
ui->setupUi(this);
a = new A();
b = new B();
c = new C();
a->moveToThread(&thread_a);
b->moveToThread(&thread_b);
c->moveToThread(&thread_c);
connect(a, SIGNAL(ready(QString, QVector<double>)), this, SLOT(handlerA(QString, QVector<double>)));
connect(b, SIGNAL(ready(QString, QVector<double>)), this, SLOT(handlerB(QString, QVector<double>)));
connect(c, SIGNAL(ready(QString, QVector<double>)), this, SLOT(handlerC(QString, QVector<double>)));
thread_a.start();
thread_b.start();
thread_c.start();
}
MainWindow::~MainWindow() {
thread_a.wait();
thread_b.wait();
thread_c.wait();
delete ui;
}
void MainWindow::handlerA(QString str, QVector<double> v) {
QVector<double> x = v;
ui->lbl_a->setText(str);
}
void MainWindow::handlerB(QString str, QVector<double> v) {
QVector<double> x = v;
ui->lbl_b->setText(str);
}
void MainWindow::handlerC(QString str, QVector<double> v) {
QVector<double> x = v;
ui->lbl_c->setText(str);
}
void MainWindow::on_btn_start_clicked() {
a->doWork();
b->doWrok();
c->doWork();
}
I expected that lbl_a will appear first and then lbl_b and then lbl_c but no matter how I change the for loop they always appear together.
What is the problem?
You are not executing the for
loops in each thread. You are executing them all in the same thread, the main
thread.
This is because you are calling directly the function doWork
from the slot on_btn_start_clicked
, behaving as a normal function.
You should remove entirely the calls to doWork
.
Instead, connect the signal QThread::started()
to your doWork
function. With this, once the thread has started, it will emit this signal from the new thread, executing your doWork
function from the thread.
connect(&thread_a, &QThread::started, a, &A::doWork);
Of course, a
, b
and c
have to be QObjects, and the functions doWork
must be slots.
Note: Starting from Qt 5.10 and C++17, you can use also the static function QThread::create, which creates a thread and upon starting, it will execute the passed function.