QThread的多线程用法

QThread 类是 Qt 线程模块中的核心类之一,它是一个与操作系统本身的线程模型对应的、可跨平台的线程抽象类,允许开发者创建自己的多线程应用程序。QThread 类将一个线程封装成了对象,使得线程可以在不同的上下文(如主线程或子线程)中进行管理和控制,而无需直接使用传统的线程库函数并处理复杂的线程同步问题。

在使用 QThread 进行多线程编程时,通常需要继承该类并实现其 run() 函数以完成线程运行的任务。run() 函数是 QThread 类的纯虚函数,开发者需要在该函数中编写具体的线程代码,并确保该函数终止后线程的生命周期也随之结束。除此之外,QThread 类还提供了一系列其他函数,用于控制线程的状态和执行轨迹,如:

  • start():启动线程,并自动调用 QThread 对象的 run() 函数。
  • wait():等待线程的结束,并阻塞调用线程,直到目标线程执行完毕。
  • terminate():强制终止线程,可能导致资源泄露和未定义行为,不推荐使用。
  • quit() / exit():请求线程停止,并安全退出线程事件循环。

在使用 QThread 时需要注意一些常见的问题,如线程安全、同步互斥、内存管理等,这些问题也是多线程编程中常见的难点。因此,Qt 提供了一系列其他的线程类和工具类,如 QMutex、QReadWriteLock、QSemaphore、QWaitCondition 等,帮助开发者更方便地控制线程同步和互斥访问共享资源的问题。

QThread有两种使用方式,可根据实际需求选择不同的使用场景。

直接继承 QThread 类

该方式主要用于需要在新线程中执行独立的任务,该任务不涉及到其他对象的运行和控制。此时最好直接使用继承 QThread 类的方式来创建新线程。这种方式实现简单,易于理解。

#include <QThread>
#include <QDebug>
#include <QCoreApplication>

class MyThread : public QThread
{
public:
    void run() override {
        qDebug() << "Thread ID:" << QThread::currentThreadId();
        // 在这里编写具体的线程任务代码
    }
};

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

    qDebug() << "Main thread ID:" << QThread::currentThreadId();
    MyThread thread;
    thread.start();  // 启动线程
    thread.wait();   // 等待线程执行完毕
    return a.exec();
}

使用 moveToThread 函数移动对象

该方式主要用于需要将一个对象从主线程移到新线程中,并且在新线程中使用该对象与其他对象进行交互和控制的场合。这种方式适合于多线程编程中经常用到的需求,如网络通信、I/O 等阻塞操作。实现相对较为灵活,可以调用对象的槽函数来启动新线程并处理数据。

需要注意的是,如果有多个对象需要在同一个线程中运行,则必须保证它们之间的竞争条件,并且不能产生死锁等问题,必要时需要使用互斥量或其他线程同步机制以确保程序正确性。同时,为了避免内存泄漏,当不再需要某些线程或对象时,应及时删除相关资源。

#ifndef WORKER_H
#define WORKER_H

#include <QObject>
#include <QThread>
#include <QDebug>

class Worker : public QObject
{
    Q_OBJECT

public:
    Worker() {}
    virtual ~Worker(){}

public slots:
    void doWork() {
        qDebug() << "Worker thread ID: " << QThread::currentThreadId();
    }
};

#endif // WORKER_H
#include <QCoreApplication>
#include <QDebug>
#include <QObject>
#include <QThread>
#include "worker.h"


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

    // 创建一个新线程
    QThread* thread = new QThread();

    // 创建一个 Worker 对象并将其移动到新线程中
    Worker* worker = new Worker();
    worker->moveToThread(thread);

    qDebug() << "Main thread ID:" << QThread::currentThreadId();

    // 在新线程中启动 Worker 的 doWork() 槽函数
    QObject::connect(thread, &QThread::started, worker, &Worker::doWork);
    thread->start();

    // 等待线程执行完毕
    thread->wait();

    return a.exec();
}

需要注意的是,如果在主线程中直接调用wrker的槽函数,则该槽函数仍然在主线程执行。

lambda表达式结合QThread

还有一些场景,使用 lambda 表达式来实现 QThread 类的多线程可以有效地减少代码复杂度和维护成本。

// 主线程中
QThread* thread = new QThread();

// 创建 QUdpSocket 套接字对象
QUdpSocket* socket = new QUdpSocket();
socket->moveToThread(thread);

// 绑定信号槽
QObject::connect(thread, &QThread::started, [&]{
    socket->bind(QHostAddress::AnyIPv4, 12345);
    QObject::connect(socket, &QUdpSocket::readyRead, [&]{
        while (socket->hasPendingDatagrams()) {
            QByteArray datagram;
            datagram.resize(socket->pendingDatagramSize());
            socket->readDatagram(datagram.data(), datagram.size());

            // 在子线程中处理数据
        }
    });
});

thread->start();

在上述代码中,我们先在主线程中创建了 QUdpSocket 套接字对象,并使用 moveToThread() 方法将其移动到了新开启的子线程中。接着在在子线程中绑定 readyRead 信号,在 lambda 函数中循环调用 hasPendingDatagrams() 和 readDatagram() 函数以接收和处理数据。

需要注意的是:在将套接字对象移动到其他线程中时,我们必须要在目标线程中创建该对象,否则可能出现程序崩溃或者无法接收到数据的问题。同时也需要注意不要对一个已经绑定了信号槽的套接字对象进行移动操作,否则会导致连接失效。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
PyQt是Python语言的GUI编程工具包,而QThreadQt框架中线程管理的类,可以用于多线程编程。 在PyQt中使用QThread可以通过继承QThread类实现。下面是一个使用QThread的示例代码: ```python from PyQt5.QtCore import QThread, pyqtSignal class Worker(QThread): finished = pyqtSignal() progress = pyqtSignal(int) def __init__(self, parent=None): super(Worker, self).__init__(parent) def run(self): for i in range(100): self.progress.emit(i) self.finished.emit() ``` 在上面的代码中,我们定义了一个Worker类,继承了QThread类。在Worker类中,我们定义了两个信号,finished和progress,分别用于表示任务结束和任务进度。在run方法中,我们模拟了一个任务,每次循环都会发射progress信号,表示任务的进度。当任务结束后,发射finished信号。 下面是一个使用Worker类的示例代码: ```python from PyQt5.QtWidgets import QApplication, QMainWindow, QProgressBar from PyQt5.QtCore import Qt import sys class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle('QThread Example') self.setGeometry(100, 100, 400, 300) self.progressbar = QProgressBar(self) self.progressbar.setGeometry(50, 50, 300, 30) self.progressbar.setValue(0) self.worker = Worker() self.worker.progress.connect(self.setProgress) self.worker.finished.connect(self.taskFinished) self.worker.start() def setProgress(self, value): self.progressbar.setValue(value) def taskFinished(self): print('Task finished') if __name__ == '__main__': app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_()) ``` 在上面的代码中,我们创建了一个窗口,并在窗口中添加了一个进度条。在MainWindow类的构造函数中,我们创建了一个Worker对象,并将它的progress信号连接到setProgress方法上,将它的finished信号连接到taskFinished方法上。然后,我们启动了Worker对象。 在setProgress方法中,我们设置进度条的值;在taskFinished方法中,我们打印一条消息表示任务结束。 以上就是使用PyQtQThread进行多线程编程的示例代码。如果您有任何问题,请随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zw_ggr_2017

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值