当前位置:   article > 正文

[QT编程系列-25]:多线程机制 - QThread和MoveToThread简介_qthread movetothread

qthread movetothread

目录

第1章 简介

1.1 多线程的目的

1.2 QThread多线程使用方法

1.3 QT支持多线的步骤

第2章 QThread

2.1 概述

2.2 moveToThread


第1章 简介

1.1 多线程的目的

QThread类提供了一个与平台无关的管理线程的方法。

在Qt中建立线程的主要目的就是为了用线程来处理那些耗时的后台操作,比如大量运算,复制大文件,网络传输等。

QT(也称为Qt框架)是一个用于开发跨平台应用程序的C++库。它提供了丰富的功能,包括多线程支持。

多线程是一种在同一时间处理多个任务的技术,它可以改善应用程序的响应性和性能

1.2 QThread多线程使用方法

1.  自定义Thread继承QThread类

2. QObject::moveToThread()

第2章 QThread

2.1 QThread支持多线程的步骤

在QT中使用多线程可以通过以下几个步骤来实现:

  1. 引入Qt多线程相关的类:在你的代码中引入/包含以下类的头文件:QThreadQRunnable、QThreadPool、QObject等。

  2. 创建一个继承自QThread或QRunnable的类:这个类将被用来执行需要在后台线程中运行的任务。如果你需要更多的灵活性和控制,可以选择继承自QThread,否则继承自QRunnable会更简单。

  3. 重写run()方法:在你的自定义类中重写run()方法,并在其中实现你的任务逻辑。

  4. 创建并启动线程:在主线程中创建你的自定义类的实例,然后调用start()方法来启动线程。这将自动调用你的run()方法。

以下是一个简单的示例代码,展示了如何在QT中使用多线程:

  1. #include <QThread>
  2. #include <QDebug>
  3. class MyThread : public QThread
  4. {
  5. Q_OBJECT
  6. public:
  7. void run() override
  8. {
  9. // 执行你的任务逻辑
  10. qDebug() << "Hello from thread";
  11. }
  12. };
  13. int main(int argc, char *argv[])
  14. {
  15. QApplication app(argc, argv);
  16. MyThread thread;
  17. thread.start();
  18. // 主线程继续执行其他任务
  19. qDebug() << "Hello from main thread";
  20. return app.exec();
  21. }

在上面的例子中,我们创建了一个名为MyThread的类,继承自QThread。我们重写了run()方法,其中打印了一条消息。在main()函数中,我们创建了一个MyThread实例,并调用它的start()方法来启动线程。同时,主线程也继续执行其他任务。当运行这个程序时,你会看到两条消息,一条来自主线程,一条来自子线程。

需要注意的是,当使用多线程编程时,需要小心处理线程间的共享数据访问,避免出现竞争条件和其他线程相关的问题。QT提供了一些同步工具,如互斥锁和信号量,来帮助你实现线程间的安全数据访问。

Qt提供了强大的多线程支持,使开发者能够轻松地在应用程序中实现并发和并行处理。

以下是Qt多线程支持的一些重要组件和功能:

  1. QThread类:QThread是Qt提供的多线程编程的基础类。开发者可以通过继承QThread类来创建自己的线程类,并实现run()函数来定义线程的执行逻辑。

  2. 信号和槽机制:Qt的信号和槽机制是一个强大的线程间通信机制。线程间的对象通信可以通过信号和槽的方式来实现,无需直接操作共享数据。这种机制可以有效地降低多线程编程的复杂性。

  3. QMutex类:QMutex是一个互斥锁类,用于保护共享数据的访问。通过QMutex,你可以确保在同一时间只有一个线程可以访问被保护的代码区域,从而避免竞态条件。

  4. QWaitCondition类:QWaitCondition是一个条件变量类,用于线程间的等待和唤醒操作。通过QWaitCondition,你可以实现线程的等待直到某个条件满足,并在条件满足时唤醒线程。

  5. QThreadPool类:QThreadPool是负责管理和调度线程的线程池类。通过QThreadPool,你可以将任务提交到池中,线程池会自动为你管理线程的生命周期和任务的执行。

除了上述的核心组件,Qt还提供了其他一些辅助类和工具,如QReadWriteLock(读写锁)、QSemaphore(信号量)、 QtConcurrent(并行编程框架)等,这些类和工具都可以帮助你更好地处理多线程编程。

在使用Qt多线程时,需要注意以下几点:

  1. 避免对共享数据的直接访问:尽量不要直接操作共享数据,而是通过信号和槽或使用互斥锁等机制来确保线程安全。

  2. 避免长时间阻塞主线程:如果在主线程中有耗时的操作,应该将其放入后台线程以避免阻塞主线程,保证应用程序的响应性。

  3. 小心使用线程间传递的数据:在线程间传递数据时需要注意数据的有效性和生命周期,避免出现悬空指针或无效引用等问题。

Qt的多线程支持可以帮助你更轻松地编写多线程应用程序,并在并发和并行处理方面提供了很大的便利性。通过合理地使用Qt的多线程功能,你可以提高应用程序的性能和响应性,并更好地利用多核处理器的计算能力。

2.2 QThread讲解

QThread是Qt提供的一个类,用于在应用程序中创建和管理线程。

它封装了底层的线程操作,使多线程编程变得更加方便和可管理。

以下是一些使用QThread的一般步骤和常见用法:

  1. 创建一个自定义的QThread子类,重写其run()函数。run()函数是在线程启动时执行的入口点,你可以在其中编写你的线程逻辑。
  1. class MyThread : public QThread {
  2. public:
  3. void run() override {
  4. // 编写线程逻辑
  5. }
  6. };
  1. 创建MyThread类的实例,并调用start()函数来启动线程。
  1. MyThread* thread = new MyThread();
  2. thread->start();

  1. 可选地,连接信号和槽以进行线程间通信。你可以使用Qt的信号和槽机制来在主线程和子线程之间进行通信。
  1. connect(someObject, &SomeObject::someSignal, thread, &MyThread::someSlot);
  2. // 或者反向连接
  3. connect(thread, &MyThread::someSignal, someObject, &SomeObject::someSlot);

  1. 在需要的时候,可以调用wait()函数来等待子线程的结束。也可以调用quit()或terminate()函数来停止线程。
  1. thread->wait(); // 等待线程结束
  2. thread->quit(); // 请求线程退出
  3. thread->terminate(); // 强制终止线程

  1. 检查线程的状态和控制线程行为。你可以使用QThread的函数来获取线程的当前状态,例如isRunning()、isFinished()、isInterruptionRequested()等。
  1. if (thread->isRunning()) {
  2. // 线程正在运行
  3. }

QThread还提供了其他一些辅助功能,例如设置线程的优先级、设置线程栈的大小、事件循环和事件处理等。

需要注意的是,直接继承QThread并重写run()函数是一种使用QThread的传统方式。但是从Qt 5.2版本开始,Qt提供了一种更简单和更推荐的方式来处理多线程,即使用Qt的信号和槽机制与QRunnable和QThreadPool或Qt Concurrent组合使用。

希望这些信息对使用QThread类来创建和管理线程有所帮助。如果有任何进一步的问题,请随时提问。

2.3 QThread成员函数

QThread类是Qt中用于创建和管理线程的类,它提供了许多成员函数来管理线程的行为和状态。

以下是QThread类中一些常见的成员函数:

  1. start():启动线程,使其以独立线程的方式开始执行run()函数中的代码。

  2. run():需要在子类中重新实现的虚函数,定义线程执行的主要代码逻辑。

  3. wait():阻塞当前线程,直到线程执行完成。

  4. sleep():使当前线程睡眠指定的毫秒数。

  5. terminate():终止线程的执行。这是一种比较粗暴的方法,通常不推荐使用。

  6. quit():停止线程的事件循环,推出线程执行。通常与event loop(事件循环)一起使用。

  7. msleep():使当前线程睡眠指定的毫秒数。

  8. usleep():使当前线程睡眠指定的微秒数。

  9. isRunning():判断线程是否正在执行。

  10. currentThreadId():返回当前线程的唯一标识符。

  11. priority() / setPriority():获取或设置线程的优先级。

  12. finished():当线程执行完成时发出的信号。

  13. started():当线程开始执行时发出的信号。

  14. finished():在线程执行完成后,由QThread对象发出的信号。

  15. moveToThread(QThread* thread):将对象移动到指定的线程中运行。

这只是QThread类中的一些常见成员函数,通过使用这些函数,可以管理线程的执行、状态和行为。根据具体的应用需求,可能会使用更多的QThread成员函数来完成线程的管理和操作。

第3章  moveToThread

3.1 概述

moveToThread()是一个Qt中的成员函数,用于将对象移到指定的线程中执行。

它允许您在多线程应用程序中管理对象的线程执行上下文

以下是moveToThread()函数的语法和用法:

void QObject::moveToThread(QThread* thread)
  • thread:指向目标线程的指针。

moveToThread()函数的作用是将调用该函数的对象与指定的线程相关联。

这意味着对象的方法和事件将在目标线程的上下文中执行,而不是在调用线程(创建对象的线程)的上下文中执行。

以下是一个使用moveToThread()函数的示例:

  1. #include <QObject>
  2. #include <QDebug>
  3. #include <QThread>
  4. class Worker : public QObject {
  5. Q_OBJECT
  6. public slots:
  7. void doWork() {
  8. qDebug() << "Worker thread:" << QThread::currentThread();
  9. // 执行耗时操作
  10. }
  11. };
  12. int main(int argc, char *argv[]) {
  13. QCoreApplication app(argc, argv);
  14. qDebug() << "Main thread:" << QThread::currentThread();
  15. // 创建一个新的管理线程上下文的对象
  16. QThread* workerThread = new QThread;
  17. // 创建一个可以task对象,该对象可以执行某种操作,比如while循环的函数
  18. Worker* worker = new Worker;
  19. // 将Worker对象移到 workerThread 线程
  20. // 如果没有这行代码,则worker的task在创建worker线程中执行,而不是目标线程上下文中执行
  21. worker->moveToThread(workerThread);
  22. // 当线程启动时,执行 Worker 的 doWork() 槽函数
  23. // 线程QThread也是类的对象,因此,可以通过槽函数和信号在对象间通信:
  24. // 在QThread对象中执行另一个需要循环执行的对象的成员函数(while循环)
  25. QObject::connect(workerThread, &QThread::started, worker, &Worker::doWork);
  26. //在QThread对象的上下文中发送一个started信号,在QThread线程对象的上下文中执行worker对象中的槽函数,该槽函数是一个while循环执行的函数。
  27. workerThread->start();
  28. return app.exec();
  29. }

在上面的示例中,我们创建了一个Worker类,该类继承自QObjectWorker类中定义了一个doWork()方法用于执行耗时的工作。

在主函数中,我们创建了一个worker对象和一个workerThread线程对象。然后,使用moveToThread()worker对象移动到workerThread线程中。这样,worker对象的doWork()方法将在workerThread线程中执行。

通过连接workerThreadstarted信号与workerdoWork()槽函数,当线程启动时,doWork()方法将自动被调用。

需要注意的是,moveToThread()函数只能在对象所属的线程中调用,否则会导致未定义的行为。因此,建议在创建对象后尽早调用moveToThread()函数来确保对象在预期的线程中执行。

moveToThread()函数在多线程编程中非常有用,它允许您将对象移动到适当的线程,并在该线程中执行相关的方法和事件处理。这有助于将耗时的操作与UI交互分开,保持应用程序的响应性。

第4章  QThread与moveToThread创建线程的比较

4.1 代码实例

  1. #include "mainwindow.h"
  2. #include <QApplication>
  3. #include <QThread>
  4. #include <QDebug>
  5. #include <QObject>
  6. #include <QWidget>
  7. class MyThread : public QThread {
  8. public:
  9. void run() override {
  10. qDebug() << "Run Thread started";
  11. // 在这里执行耗时任务
  12. int i = 0;
  13. while(1)
  14. {
  15. sleep(3);
  16. qDebug() << i << ": run thread:" << QThread::currentThread();
  17. i++;
  18. }
  19. qDebug() << "Run Thread finished";
  20. }
  21. };
  22. class MyWorker : public QObject {
  23. Q_OBJECT
  24. public slots:
  25. void doWork() {
  26. qDebug() << "doWork Thread started";
  27. while(1){
  28. qDebug() << "Worker thread:" << QThread::currentThread();
  29. // 执行耗时操作
  30. QThread::sleep(3);
  31. }
  32. qDebug() << "doWork Thread finished";
  33. }
  34. };
  35. int main(int argc, char *argv[])
  36. {
  37. QApplication a(argc, argv);
  38. MainWindow w;
  39. qDebug() << "Main thread started: " << QThread::currentThread() ;
  40. // 创建并启动run线程1
  41. MyThread thread_run1;
  42. thread_run1.start();
  43. // 创建并启动run线程2
  44. MyThread thread_run2;
  45. thread_run2.start();
  46. //创建一个管理线程上下文的对象
  47. QThread* workerThread1 = new QThread;
  48. //创建一个task对象
  49. MyWorker* myworker1 = new MyWorker;
  50. // 将 Worker 对象移到 workerThread 线程
  51. //myworker1->moveToThread(workerThread1);
  52. // 当线程启动时,执行 Worker 的 doWork() 槽函数
  53. // 线程也是一个对象,因此可以使用对象之间的通信机制,进行通信
  54. QObject::connect(workerThread1, &QThread::started, myworker1, &MyWorker::doWork);
  55. workerThread1->start();
  56. //创建一个管理线程上下文的对象
  57. QThread* workerThread2 = new QThread;
  58. //创建一个task对象
  59. MyWorker* myworker2 = new MyWorker;
  60. // 将 Worker 对象移到 workerThread 线程
  61. myworker2->moveToThread(workerThread2);
  62. // 当线程启动时,执行 Worker 的 doWork() 槽函数
  63. // 线程也是一个对象,因此可以使用对象之间的通信机制,进行通信
  64. QObject::connect(workerThread2, &QThread::started, myworker2, &MyWorker::doWork);
  65. workerThread2->start();
  66. qDebug() << "Main thread finished" << QThread::currentThread() ;
  67. w.show();
  68. return a.exec();
  69. }

4.2 输出结果

Main thread started: QThread(0x9c7770)

Main thread finished QThread(0x9c7770)

Run Thread started

Run Thread started

doWork Thread started

Worker thread: QThread(0x30593d0)

doWork Thread started

Worker thread: QThread(0x9c7770 //没有myworker1->moveToThread(workerThread1),因此,在主线程上下文中执行,因此,执行比较缓慢,滞后于workerThread2上下文的myworker2

0 : run thread: QThread(0x8bfc30)

0 : run thread: QThread(0x8bfc20)

Worker thread: QThread(0x30593d0)

Worker thread: QThread(0x9c7770)

1 : run thread: QThread(0x8bfc30)

1 : run thread: QThread(0x8bfc20)

Worker thread: QThread(0x30593d0)

Worker thread: QThread(0x9c7770)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/305102
推荐阅读
相关标签
  

闽ICP备14008679号