Qt线程简介
从 Qt4.4 版本之后,因为 QThread 的 run 方法创建新线程这样实现与 Qt 设计的理念不符,Qt 主推使用 moveToThread 方法来创建新线程。QThread 应该被看做是操作系统线程的接口或控制点,而不应该包含需要在新线程中运行的代码。需要运行的代码应该放到一个 QObject 的子类中,然后将该子类的对象 moveToThread 到新线程中。主要操作步骤如下:
- 创建一个类对象 obj,创建一个线程对象 thread。
- 创建主线程中对象 M 与类对象 obj 链接的信号槽。
- 通过类对象 obj 的 moveToThread 方法将类对象 obj 移动到线程对象 thread 中。
- 调用线程对象 thread 的 start 方法,启动线程。
- 对象 M 调用信号槽,类对象 obj 在新线程中处理数据(调用新线程只能通过信号槽来完成,如果要将类对象 obj 的数据传回给对象 M,可以由 obj 发起对 M 的信号槽)。
具体代码如下:
1:要放入新线程的 Worker 类
h 文件:
#ifndef WORKER_H
#define WORKER_H#include <QObject>/*****************************************************************************************@copyright 2013-2020@author qiaowei@contact weiweiqiao@126.com@version 1.0@date 2021-01-09@brief 工人类,主要方法do_something打印工人对象所在线程的id
******************************************************************************************/
class Worker : public QObject
{Q_OBJECT
public:explicit Worker(QObject *parent = nullptr);signals:/***************************************************************************@author qiaowei@version 1.0@date 2021-01-24@brief 调用Controller::print_thread方法***************************************************************************/void result_ready(const QString& content);public slots:/***************************************************************************@author qiaowei@version 1.0@date 2021-01-07@brief 打印Worker对象所在线程id***************************************************************************/void do_something();};#endif // WORKER_H
cpp 文件:
#include <QtDebug>
#include <QThread>
#include "worker.h"Worker::Worker(QObject *parent) : QObject(parent)
{}void Worker::do_something()
{emit result_ready("Hello");// int i(0);
// while (i < 20) {
// qDebug() << "I'm working in Worker's thread:" << (quint64) QThread::currentThreadId();
// ++i;
// }qDebug() << "I'm working in Worker's thread:" << (quint64) QThread::currentThreadId();
}
2:操纵 Worker 类对象的 Controller 类
h 文件:
#ifndef CONTROLLER_H
#define CONTROLLER_H#include <QObject>QT_BEGIN_NAMESPACE
class Worker;
QT_END_NAMESPACE/*****************************************************************************************@copyright 2013-2020@author qiaowei@contact weiweiqiao@126.com@version 1.0@date 2021-01-06@brief 控制线程创建、启动
******************************************************************************************/
class Controller : public QObject
{Q_OBJECT
public:explicit Controller(QObject *parent = nullptr);~Controller();/***************************************************************************@author qiaowei@version 1.0@date 2021-01-06@brief 将对象worker_移入子线程work_thread_,启动子线程***************************************************************************/void move_work_to_thread();signals:/***************************************************************************@author qiaowei@version 1.0@date 2021-01-07@brief 调用worker_::do_something方法***************************************************************************/void start_running();public slots:void print_thread() const;private:void setup_connections();void print_thread_id() const;private:/***************************************************************************@author qiaowei@version 1.0@date 2021-01-07@brief 子线程***************************************************************************/QThread* work_thread_;/***************************************************************************@author qiaowei@version 1.0@date 2021-01-07@brief 放入子线程work_thread_的对象worker_***************************************************************************/Worker* worker_;
};#endif // CONTROLLER_H
cpp 文件:
#include <QThread>
#include <QtDebug>
#include "controller.h"#include "worker.h"Controller::Controller(QObject *parent) :QObject(parent),work_thread_(new QThread()),worker_(new Worker())
{setup_connections();print_thread_id();move_work_to_thread();
}Controller::~Controller()
{work_thread_->quit();work_thread_->wait();delete work_thread_;if (nullptr == work_thread_) {qDebug()<< "nullptr";} else {work_thread_ = nullptr;}
}void Controller::move_work_to_thread()
{worker_->moveToThread(work_thread_);// 启动子线程。不启动子线程,worker_对象的方法不会被调用(因为运行的环境没启动)work_thread_->start();
}void Controller::print_thread() const
{
// int i(0);
//
// while (i < 20) {
// print_thread_id();
// ++i;
// }print_thread_id();
}void Controller::setup_connections()
{connect(this,&Controller::start_running,worker_,&Worker::do_something);connect(worker_,&Worker::result_ready,this,&Controller::print_thread);
}void Controller::print_thread_id() const
{qDebug()<< "Controller::Controller = " << (quint64) QThread::currentThreadId();
}
触发线程的 ui 类
h 文件:
#ifndef CONTROLLER_DIALOG_H
#define CONTROLLER_DIALOG_H#include <QDialog>QT_BEGIN_NAMESPACE
class Controller;
QT_END_NAMESPACEnamespace Ui {
class Controller_dialog;
}/*****************************************************************************************@copyright 2013-2020@author qiaowei@contact weiweiqiao@126.com@version 1.0@date 2021-01-09@brief 操作多线程的ui
******************************************************************************************/
class Controller_dialog : public QDialog
{Q_OBJECTpublic:explicit Controller_dialog(QWidget *parent = nullptr);~Controller_dialog();private:void setup_connections();private:Ui::Controller_dialog *ui;Controller* controller_;
};#endif // CONTROLLER_DIALOG_H
cpp 文件:
#include "controller_dialog.h"
#include "ui_controller_dialog.h"#include "controller.h"Controller_dialog::Controller_dialog(QWidget *parent) :QDialog(parent),ui(new Ui::Controller_dialog),controller_(new Controller())
{ui->setupUi(this);setup_connections();setFixedSize(sizeHint());
}Controller_dialog::~Controller_dialog()
{delete ui;delete controller_;
}void Controller_dialog::setup_connections()
{// 启动新线程connect(ui->start_button_,&QPushButton::clicked,controller_,&Controller::start_running);// 关闭所有窗体,退出程序connect(ui->quit_button_,&QPushButton::clicked,qApp,&QApplication::closeAllWindows);
}
界面 ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Controller_dialog</class><widget class="QDialog" name="Controller_dialog"><property name="geometry"><rect><x>0</x><y>0</y><width>219</width><height>83</height></rect></property><property name="windowTitle"><string>Dialog</string></property><layout class="QGridLayout" name="gridLayout"><item row="0" column="0"><layout class="QHBoxLayout" name="horizontalLayout"><item><widget class="QPushButton" name="start_button_"><property name="text"><string>Start Button</string></property></widget></item><item><widget class="QPushButton" name="quit_button_"><property name="text"><string>Quit</string></property></widget></item></layout></item></layout></widget><resources/><connections/>
</ui>
main 文件:
#include <QApplication>#include "mainwindow.h"
#include "thread_dialog.h"
#include "controller_dialog.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Controller_dialog d;d.show();return a.exec();
}
运行结果,打印 Print_thread、Worker 对象的线程号:
可以看到打印结果,Worker 对象在线程 9480,主程序入口在线程 5336