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_NAMESPACE
namespace 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_OBJECT
public:
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