Qt QThread的moveToThread方法使用

£神魔★判官ぃ 2023-10-14 13:43 129阅读 0赞

Qt线程简介

从 Qt4.4 版本之后,因为 QThread 的 run 方法创建新线程这样实现与 Qt 设计的理念不符,Qt 主推使用 moveToThread 方法来创建新线程。QThread 应该被看做是操作系统线程的接口或控制点,而不应该包含需要在新线程中运行的代码。需要运行的代码应该放到一个 QObject 的子类中,然后将该子类的对象 moveToThread 到新线程中。主要操作步骤如下:

  1. 创建一个类对象 obj,创建一个线程对象 thread。
  2. 创建主线程中对象 M 与类对象 obj 链接的信号槽。
  3. 通过类对象 obj 的 moveToThread 方法将类对象 obj 移动到线程对象 thread 中。
  4. 调用线程对象 thread 的 start 方法,启动线程。
  5. 对象 M 调用信号槽,类对象 obj 在新线程中处理数据(调用新线程只能通过信号槽来完成,如果要将类对象 obj 的数据传回给对象 M,可以由 obj 发起对 M 的信号槽)。

具体代码如下:

1:要放入新线程的 Worker 类

h 文件:

  1. #ifndef WORKER_H
  2. #define WORKER_H
  3. #include <QObject>
  4. /*****************************************************************************************
  5. @copyright 2013-2020
  6. @author qiaowei
  7. @contact weiweiqiao@126.com
  8. @version 1.0
  9. @date 2021-01-09
  10. @brief 工人类,主要方法do_something打印工人对象所在线程的id
  11. ******************************************************************************************/
  12. class Worker : public QObject
  13. {
  14. Q_OBJECT
  15. public:
  16. explicit Worker(QObject *parent = nullptr);
  17. signals:
  18. /***************************************************************************
  19. @author qiaowei
  20. @version 1.0
  21. @date 2021-01-24
  22. @brief 调用Controller::print_thread方法
  23. ***************************************************************************/
  24. void result_ready(const QString& content);
  25. public slots:
  26. /***************************************************************************
  27. @author qiaowei
  28. @version 1.0
  29. @date 2021-01-07
  30. @brief 打印Worker对象所在线程id
  31. ***************************************************************************/
  32. void do_something();
  33. };
  34. #endif // WORKER_H

cpp 文件:

  1. #include <QtDebug>
  2. #include <QThread>
  3. #include "worker.h"
  4. Worker::Worker(QObject *parent) : QObject(parent)
  5. {
  6. }
  7. void Worker::do_something()
  8. {
  9. emit result_ready("Hello");
  10. // int i(0);
  11. // while (i < 20) {
  12. // qDebug() << "I'm working in Worker's thread:" << (quint64) QThread::currentThreadId();
  13. // ++i;
  14. // }
  15. qDebug() << "I'm working in Worker's thread:" << (quint64) QThread::currentThreadId();
  16. }

2:操纵 Worker 类对象的 Controller 类

h 文件:

  1. #ifndef CONTROLLER_H
  2. #define CONTROLLER_H
  3. #include <QObject>
  4. QT_BEGIN_NAMESPACE
  5. class Worker;
  6. QT_END_NAMESPACE
  7. /*****************************************************************************************
  8. @copyright 2013-2020
  9. @author qiaowei
  10. @contact weiweiqiao@126.com
  11. @version 1.0
  12. @date 2021-01-06
  13. @brief 控制线程创建、启动
  14. ******************************************************************************************/
  15. class Controller : public QObject
  16. {
  17. Q_OBJECT
  18. public:
  19. explicit Controller(QObject *parent = nullptr);
  20. ~Controller();
  21. /***************************************************************************
  22. @author qiaowei
  23. @version 1.0
  24. @date 2021-01-06
  25. @brief 将对象worker_移入子线程work_thread_,启动子线程
  26. ***************************************************************************/
  27. void move_work_to_thread();
  28. signals:
  29. /***************************************************************************
  30. @author qiaowei
  31. @version 1.0
  32. @date 2021-01-07
  33. @brief 调用worker_::do_something方法
  34. ***************************************************************************/
  35. void start_running();
  36. public slots:
  37. void print_thread() const;
  38. private:
  39. void setup_connections();
  40. void print_thread_id() const;
  41. private:
  42. /***************************************************************************
  43. @author qiaowei
  44. @version 1.0
  45. @date 2021-01-07
  46. @brief 子线程
  47. ***************************************************************************/
  48. QThread* work_thread_;
  49. /***************************************************************************
  50. @author qiaowei
  51. @version 1.0
  52. @date 2021-01-07
  53. @brief 放入子线程work_thread_的对象worker_
  54. ***************************************************************************/
  55. Worker* worker_;
  56. };
  57. #endif // CONTROLLER_H

cpp 文件:

  1. #include <QThread>
  2. #include <QtDebug>
  3. #include "controller.h"
  4. #include "worker.h"
  5. Controller::Controller(QObject *parent) :
  6. QObject(parent),
  7. work_thread_(new QThread()),
  8. worker_(new Worker())
  9. {
  10. setup_connections();
  11. print_thread_id();
  12. move_work_to_thread();
  13. }
  14. Controller::~Controller()
  15. {
  16. work_thread_->quit();
  17. work_thread_->wait();
  18. delete work_thread_;
  19. if (nullptr == work_thread_) {
  20. qDebug()<< "nullptr";
  21. } else {
  22. work_thread_ = nullptr;
  23. }
  24. }
  25. void Controller::move_work_to_thread()
  26. {
  27. worker_->moveToThread(work_thread_);
  28. // 启动子线程。不启动子线程,worker_对象的方法不会被调用(因为运行的环境没启动)
  29. work_thread_->start();
  30. }
  31. void Controller::print_thread() const
  32. {
  33. // int i(0);
  34. //
  35. // while (i < 20) {
  36. // print_thread_id();
  37. // ++i;
  38. // }
  39. print_thread_id();
  40. }
  41. void Controller::setup_connections()
  42. {
  43. connect(this,
  44. &Controller::start_running,
  45. worker_,
  46. &Worker::do_something);
  47. connect(worker_,
  48. &Worker::result_ready,
  49. this,
  50. &Controller::print_thread);
  51. }
  52. void Controller::print_thread_id() const
  53. {
  54. qDebug()<< "Controller::Controller = " << (quint64) QThread::currentThreadId();
  55. }

触发线程的 ui 类

h 文件:

  1. #ifndef CONTROLLER_DIALOG_H
  2. #define CONTROLLER_DIALOG_H
  3. #include <QDialog>
  4. QT_BEGIN_NAMESPACE
  5. class Controller;
  6. QT_END_NAMESPACE
  7. namespace Ui {
  8. class Controller_dialog;
  9. }
  10. /*****************************************************************************************
  11. @copyright 2013-2020
  12. @author qiaowei
  13. @contact weiweiqiao@126.com
  14. @version 1.0
  15. @date 2021-01-09
  16. @brief 操作多线程的ui
  17. ******************************************************************************************/
  18. class Controller_dialog : public QDialog
  19. {
  20. Q_OBJECT
  21. public:
  22. explicit Controller_dialog(QWidget *parent = nullptr);
  23. ~Controller_dialog();
  24. private:
  25. void setup_connections();
  26. private:
  27. Ui::Controller_dialog *ui;
  28. Controller* controller_;
  29. };
  30. #endif // CONTROLLER_DIALOG_H

cpp 文件:

  1. #include "controller_dialog.h"
  2. #include "ui_controller_dialog.h"
  3. #include "controller.h"
  4. Controller_dialog::Controller_dialog(QWidget *parent) :
  5. QDialog(parent),
  6. ui(new Ui::Controller_dialog),
  7. controller_(new Controller())
  8. {
  9. ui->setupUi(this);
  10. setup_connections();
  11. setFixedSize(sizeHint());
  12. }
  13. Controller_dialog::~Controller_dialog()
  14. {
  15. delete ui;
  16. delete controller_;
  17. }
  18. void Controller_dialog::setup_connections()
  19. {
  20. // 启动新线程
  21. connect(ui->start_button_,
  22. &QPushButton::clicked,
  23. controller_,
  24. &Controller::start_running);
  25. // 关闭所有窗体,退出程序
  26. connect(ui->quit_button_,
  27. &QPushButton::clicked,
  28. qApp,
  29. &QApplication::closeAllWindows);
  30. }

界面 ui:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ui version="4.0">
  3. <class>Controller_dialog</class>
  4. <widget class="QDialog" name="Controller_dialog">
  5. <property name="geometry">
  6. <rect>
  7. <x>0</x>
  8. <y>0</y>
  9. <width>219</width>
  10. <height>83</height>
  11. </rect>
  12. </property>
  13. <property name="windowTitle">
  14. <string>Dialog</string>
  15. </property>
  16. <layout class="QGridLayout" name="gridLayout">
  17. <item row="0" column="0">
  18. <layout class="QHBoxLayout" name="horizontalLayout">
  19. <item>
  20. <widget class="QPushButton" name="start_button_">
  21. <property name="text">
  22. <string>Start Button</string>
  23. </property>
  24. </widget>
  25. </item>
  26. <item>
  27. <widget class="QPushButton" name="quit_button_">
  28. <property name="text">
  29. <string>Quit</string>
  30. </property>
  31. </widget>
  32. </item>
  33. </layout>
  34. </item>
  35. </layout>
  36. </widget>
  37. <resources/>
  38. <connections/>
  39. </ui>

main 文件:

  1. #include <QApplication>
  2. #include "mainwindow.h"
  3. #include "thread_dialog.h"
  4. #include "controller_dialog.h"
  5. int main(int argc, char *argv[])
  6. {
  7. QApplication a(argc, argv);
  8. Controller_dialog d;
  9. d.show();
  10. return a.exec();
  11. }

运行结果,打印 Print_thread、Worker 对象的线程号:

0e6bf4a811514b62b155d42f40b0de59.webp

可以看到打印结果,Worker 对象在线程 9480,主程序入口在线程 5336

发表评论

表情:
评论列表 (有 0 条评论,129人围观)

还没有评论,来说两句吧...

相关阅读

    相关 QtQThread(深入理解)

    简述 为了让程序尽快响应用户操作,在开发应用程序时经常会使用到线程。对于耗时操作如果不使用线程,UI界面将会长时间处于停滞状态,这种情况是用户非常不愿意看到的,我们可以用

    相关 QT QThread

    QThread类提供了一种独立于平台的方式来管理线程。 A.QThreads开始在run()中执行。默认情况下,run()通过调用exec()启动事件循环,并在线程内运行Q