[QT编程系列-25]:多线程机制 - 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中使用多线程:

#include 
#include 

class MyThread : public QThread
{
    Q_OBJECT
public:
    void run() override
    {
        // 执行你的任务逻辑
        qDebug() << "Hello from thread";
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MyThread thread;
    thread.start();

    // 主线程继续执行其他任务
    qDebug() << "Hello from main thread";

    return app.exec();
}

在上面的例子中,我们创建了一个名为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提供的一个类,用于在应用程序中创建和管理线程。

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

[QT编程系列-25]:多线程机制 - QThread和MoveToThread简介_第1张图片

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

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

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

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

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

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()函数的示例:

#include 
#include 
#include 

class Worker : public QObject {
    Q_OBJECT

public slots:
    void doWork() {
        qDebug() << "Worker thread:" << QThread::currentThread();
        // 执行耗时操作
    }
};

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    qDebug() << "Main thread:" << QThread::currentThread();


    // 创建一个新的管理线程上下文的对象
    QThread* workerThread = new QThread;

    // 创建一个可以task对象,该对象可以执行某种操作,比如while循环的函数
    Worker* worker = new Worker;

    // 将Worker对象移到 workerThread 线程
    // 如果没有这行代码,则worker的task在创建worker线程中执行,而不是目标线程上下文中执行
    worker->moveToThread(workerThread);

    // 当线程启动时,执行 Worker 的 doWork() 槽函数

    // 线程QThread也是类的对象,因此,可以通过槽函数和信号在对象间通信:
    // 在QThread对象中执行另一个需要循环执行的对象的成员函数(while循环)
    QObject::connect(workerThread, &QThread::started, worker, &Worker::doWork);

    //在QThread对象的上下文中发送一个started信号,在QThread线程对象的上下文中执行worker对象中的槽函数,该槽函数是一个while循环执行的函数。
    workerThread->start();

    return app.exec();
}

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

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

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

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

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

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

4.1 代码实例

#include "mainwindow.h"

#include 
#include 
#include 

#include 
#include 



class MyThread : public QThread {
public:
    void run() override {
        qDebug() << "Run Thread started";

        // 在这里执行耗时任务
        int i = 0;
        while(1)
        {
            sleep(3);
            qDebug() << i << ": run thread:" << QThread::currentThread();
            i++;
        }

        qDebug() << "Run Thread finished";
    }
};



class MyWorker : public QObject {
    Q_OBJECT

public slots:
    void doWork() {

        qDebug() << "doWork Thread started";

        while(1){
            qDebug() << "Worker thread:" << QThread::currentThread();
            // 执行耗时操作
            QThread::sleep(3);
        }

        qDebug() << "doWork Thread finished";
    }
};



int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    qDebug() << "Main thread started: " << QThread::currentThread() ;

    // 创建并启动run线程1
    MyThread thread_run1;
    thread_run1.start();

    // 创建并启动run线程2
    MyThread thread_run2;
    thread_run2.start();



    //创建一个管理线程上下文的对象
    QThread* workerThread1 = new QThread;

    //创建一个task对象
    MyWorker* myworker1 = new MyWorker;

    // 将 Worker 对象移到 workerThread 线程
    //myworker1->moveToThread(workerThread1);

    // 当线程启动时,执行 Worker 的 doWork() 槽函数
    // 线程也是一个对象,因此可以使用对象之间的通信机制,进行通信
    QObject::connect(workerThread1, &QThread::started, myworker1, &MyWorker::doWork);

    workerThread1->start();


    //创建一个管理线程上下文的对象
    QThread* workerThread2 = new QThread;

    //创建一个task对象
    MyWorker* myworker2 = new MyWorker;

    // 将 Worker 对象移到 workerThread 线程
    myworker2->moveToThread(workerThread2);

    // 当线程启动时,执行 Worker 的 doWork() 槽函数
    // 线程也是一个对象,因此可以使用对象之间的通信机制,进行通信
    QObject::connect(workerThread2, &QThread::started, myworker2, &MyWorker::doWork);

    workerThread2->start();

    qDebug() << "Main thread finished" << QThread::currentThread() ;

    w.show();
    return a.exec();
}

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)

你可能感兴趣的:(编程系列-QT,qt,c++,多线程)