Search code examples
qtqthread

how to use QThreads without sync


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?


Solution

  • 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.