如何在不同步的情况下使用 QThreads
how to use QThreads without sync
我有 3 个 classes,A、B 和 C;
这是class答:
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和C完全一样。只有 class B 中 doWork 中的循环直到 10000,而 C 中直到 100000000(8 个零)。
为了测试使用 QThreads 我创建了 3 个 QLabel:
QLabel* lbl_a;
QLabel* lbl_b;
QLabel* lbl_c;
这是我的主窗口代码:
#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();
}
我预计 lbl_a 会先出现然后 lbl_b 然后 lbl_c
但无论我如何更改 for 循环,它们总是一起出现。
有什么问题?
您没有在每个线程中执行 for
循环。您正在同一个线程中执行它们,即 main
线程。
这是因为您直接从插槽 on_btn_start_clicked
调用函数 doWork
,作为普通函数运行。
您应该完全删除对 doWork
的调用。
相反,将信号 QThread::started()
连接到您的 doWork
函数。有了这个,一旦线程启动,它将从新线程发出这个信号,从线程执行你的 doWork
函数。
connect(&thread_a, &QThread::started, a, &A::doWork);
当然,a
、b
和c
必须是QObjects,函数doWork
必须是槽
注意:从 Qt 5.10 和 C++17 开始,您还可以使用静态函数 QThread::create,它会创建一个线程,并在启动时执行传递的函数。
我有 3 个 classes,A、B 和 C;
这是class答: 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和C完全一样。只有 class B 中 doWork 中的循环直到 10000,而 C 中直到 100000000(8 个零)。
为了测试使用 QThreads 我创建了 3 个 QLabel:
QLabel* lbl_a;
QLabel* lbl_b;
QLabel* lbl_c;
这是我的主窗口代码:
#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();
}
我预计 lbl_a 会先出现然后 lbl_b 然后 lbl_c 但无论我如何更改 for 循环,它们总是一起出现。
有什么问题?
您没有在每个线程中执行 for
循环。您正在同一个线程中执行它们,即 main
线程。
这是因为您直接从插槽 on_btn_start_clicked
调用函数 doWork
,作为普通函数运行。
您应该完全删除对 doWork
的调用。
相反,将信号 QThread::started()
连接到您的 doWork
函数。有了这个,一旦线程启动,它将从新线程发出这个信号,从线程执行你的 doWork
函数。
connect(&thread_a, &QThread::started, a, &A::doWork);
当然,a
、b
和c
必须是QObjects,函数doWork
必须是槽
注意:从 Qt 5.10 和 C++17 开始,您还可以使用静态函数 QThread::create,它会创建一个线程,并在启动时执行传递的函数。