Qt5多线程编程的实现

Qt5多线程编程的实现

为什么需要多线程

在程序运行时,为了保证其正常运行及良好的用户体验,需要避免阻塞UI线程。如果所有操作都在UI线程中执行,当需要执行比较耗时或无法预知执行时间的操作时(比如下载文件、读写磁盘等),程序会出现“卡住”的状况,导致用户无法继续进行操作,程序表现为假死状态,影响用户使用体验。

Qt5多线程编程实现

在Qt5中,多线程编程的实现主要由以下几个部分组成:

QThread

QThread是一个基础的多线程类,继承自QObject。在使用时,需要自定义一个继承自QThread的子类,并重写run()函数,该函数代表子线程的执行任务。创建子线程的一般方式为创建QThread的子类对象,并使用start()函数启动run()函数执行线程任务。

// 继承QThread实现子线程
class Thread : public QThread {
public:
    void run() override {
        // 子线程任务执行代码
    }
};

// 创建并启动子线程
Thread* thread = new Thread();
thread->start();

QRunnable

QRunnable是一个轻量级的多线程类,继承自QObject,并实现了run()函数,当该类被传递给QThreadPool时,QThreadPool将自动创建一个线程并执行run()函数中的任务。创建QRunnable的一般方式是创建一个继承自QRunnable的子类,并实现run()函数。

// 继承自QRunnable实现轻量级的子线程任务
class Runnable : public QRunnable {
public:
    void run() override {
        // 子线程任务执行代码
    }
};

// 创建线程池并添加任务
QThreadPool* pool = QThreadPool::globalInstance();
Runnable* runnable = new Runnable();
pool->start(runnable);

QtConcurrent

QtConcurrent是一个较为高级的多线程类,提供了一些现成的多线程操作符,比如map()、filter()等,可以极大地简化多线程操作。和QRunnable一样,QtConcurrent也是一个轻量级的多线程类,调用时只需要传入要执行的函数及参数即可。

// QtConcurrent操作,map操作将vector中的元素进行平方,并使用QFuture等待返回
QFuture <int> future = QtConcurrent::map(vector, [](int& element) {
    return element * element;
});
future.waitForFinished();

QThreadPool

QThreadPool是多线程框架中的线程池,它可以管理线程的创建、关闭、等待及状态报告等。在使用时,需要先创建QThreadPool对象,并使用start()函数添加任务,QThreadPool会根据任务及系统性能自动管理线程数量。一旦线程池启用,只有在指定条件(如线程Idle时间、最大线程数等)下才停止工作。

// 创建线程池并添加任务
QThreadPool* pool = QThreadPool::globalInstance();
pool->setMaxThreadCount(4);
for (int i = 0; i < count; ++
    Runnable* runnable = new Runnable();
    pool->start(runnable);
}
pool->waitForDone();

示例说明

示例一:QThread实现

下面是一个使用QThread实现多线程的示例,包括主线程和子线程间的信号与槽传递。

// MyThread.h
class MyThread : public QThread {
Q_OBJECT
public:
    MyThread(QObject* parent = nullptr);
signals:
    void numberChanged(int number);
protected:
    void run() override;
};

// MyThread.cpp
MyThread::MyThread(QObject* parent)
    : QThread(parent){
}

void MyThread::run() {
    int number = 0;
    while(number < 100) {
        emit numberChanged(number);
        QThread::msleep(100);
        ++number;
    }
}

// MainWindow.h
class MainWindow : public QMainWindow {
Q_OBJECT
public:
    explicit MainWindow(QWidget* parent = nullptr);
public slots:
    void numberReceived(int number);
private slots:
    void on_pushButton_clicked();
private:
    Ui::MainWindow* ui;
    MyThread* m_thread;
};

// MainWindow.cpp
MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow) {
    ui->setupUi(this);
    m_thread = new MyThread(this);
    connect(m_thread, &MyThread::numberChanged, this, &MainWindow::numberReceived);
}

void MainWindow::numberReceived(int number) {
    ui->lineEdit->setText(QString::number(number));
}

void MainWindow::on_pushButton_clicked() {
    if(!m_thread->isRunning()) {
        m_thread->start();
    }
}

在该示例中,主线程界面中有一个push button和一个line edit,当用户点击push button时,将在子线程中启动任务,并每100ms向主线程信号槽传递数字。主线程接收到信号后,将数字显示到line edit控件中。

示例二:QtConcurrent实现

下面是一个使用QtConcurrent实现多线程的示例,实现了一个简单的对文件夹进行递归遍历并计算其所有文件大小的程序。

// DirSizeCalculator.h
class DirSizeCalculator {
public:
    qint64 getDirSize(const QString& path);
private:
    static qint64 countSize(const QString& path);
};

// DirSizeCalculator.cpp
qint64 DirSizeCalculator::getDirSize(const QString& path) {
    QFuture <qint64> future = QtConcurrent::run(&countSize, path);
    future.waitForFinished();
    return future.result();
}

qint64 DirSizeCalculator::countSize(const QString& path) {
    qint64 size = 0;
    QFileInfo file_info(path);
    if(file_info.isFile()) {
        size += file_info.size();
    } else if(file_info.isDir()) {
        QDir dir(path);
        QStringList names = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
        foreach(QString name, names) {
            QString full_path = QDir(path).filePath(name);
            if(QFileInfo(full_path).isFile()) {
                size += QFileInfo(full_path).size();
            } else if(QFileInfo(full_path).isDir()) {
                size += countSize(full_path);
            }
        }
    }
    return size;
}

// MainWindow.h
class MainWindow : public QMainWindow {
Q_OBJECT
public:
    explicit MainWindow(QWidget* parent = nullptr);
private slots:
    void on_pushButton_clicked();
private:
    Ui::MainWindow* ui;
    DirSizeCalculator* m_calculator;
};

// MainWindow.cpp
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow) {
    ui->setupUi(this);
    m_calculator = new DirSizeCalculator();
}

void MainWindow::on_pushButton_clicked() {
    QString folder_path = QFileDialog::getExistingDirectory(this, "Please select folder");
    qint64 size = m_calculator->getDirSize(folder_path);
    QString display_text = QString("Folder size: %1 Bytes").arg(size);
    ui->label->setText(display_text);
}

在该示例中,主线程界面中有一个push button和一个label,当用户点击push button时,将弹出文件夹选择对话框,当用户选择文件夹后,程序将启动QtConcurrent的线程执行DirSizeCalculator中的 getDirSize() 函数,并等待线程返回结果,线程会利用递归方式计算文件夹下所有文件的大小,并将结果返回给主线程进行显示。

总结

多线程编程的实现在Qt5中非常便捷,开发者可以根据实际需求选择合适的多线程类,避免UI线程阻塞,降低程序出现假死等异常情况的概率,提高程序可靠性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Qt5多线程编程的实现 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • 对python多线程与global变量详解

    我来给你讲解一下“对Python多线程与global变量详解”的完整攻略。 一、什么是多线程? 多线程是指在一个进程中运行多个线程,每个线程执行不同的任务,多线程可以提高程序的执行效率。 二、Python中多线程的实现 Python中多线程的实现可以使用thread和threading两个模块,其中thread模块已经被废弃,推荐使用threading模块。…

    多线程 2023年5月16日
    00
  • 高并发下如何避免重复数据产生技巧

    如何避免重复数据产生,在高并发环境下是一个非常重要的问题,因为一旦出现重复数据,就会影响整个系统的正常运行,甚至可能导致严重的数据安全问题。下面是一些可以避免重复数据产生的技巧: 数据库级别的锁定机制 在高并发环境下,一个经典的问题是“在同一时刻是否可以有多个用户同时修改同一条数据?” 事实上,这是不可能的,因为如果多个用户同时修改同一条数据,就会出现数据不…

    多线程 2023年5月17日
    00
  • Java并发系列之AbstractQueuedSynchronizer源码分析(概要分析)

    让我来为您详细讲解“Java并发系列之AbstractQueuedSynchronizer源码分析(概要分析)”的攻略且提供两条示例说明。 1. 概要分析 1.1 AQS简介 AQS(AbstractQueuedSynchronizer)是java.util.concurrent(J.U.C)中的一个关键内部类,是JUC包中实现各种同步器的基础。AQS是实现…

    多线程 2023年5月17日
    00
  • Java 多线程并发 ReentrantReadWriteLock详情

    Java 多线程并发是Java语言的一个重要特性,使程序能够同时执行多个任务。在实际开发中,为了保证数据的安全性,需要使用线程锁机制。ReentrantReadWriteLock是Java语言中非常常用的线程锁机制,它既可以保证数据的并发读取,也可以保证数据写入的线程安全性,下面我们来详细讲解一下“Java多线程并发ReentrantReadWriteLoc…

    多线程 2023年5月16日
    00
  • python多线程实现TCP服务端

    下面是实现 Python 多线程 TCP 服务端的攻略,包括如下步骤: 导入相关模块 Python 实现多线程 TCP 服务端需要用到 socket 和 threading 模块,因此需要在开头导入这两个模块: import socket import threading 创建 socket 对象 在 Python 中,使用 socket 模块的 socke…

    多线程 2023年5月16日
    00
  • Python 线程池模块之多线程操作代码

    一、Python 线程池模块简介 Python 中的 concurrent.futures 模块提供了 ThreadPoolExecutor 和 ProcessPoolExecutor 两个类,用于管理一个线程池和一个进程池。本文重点讲解 ThreadPoolExecutor 类,即用于多线程操作的线程池模块。 线程池中包含多个并发执行的线程,当有任务需要处…

    多线程 2023年5月16日
    00
  • 线程池的原理与实现详解

    线程池的原理与实现详解 什么是线程池 线程池是一种基于线程的并发编程方式,它的基本思想是:在应用程序启动之初,就创建一定数量的线程并将它们置于一个线程池中,这些线程大多是空闲状态的,并且能够接收来自应用程序提交的工作任务。这些任务被提交给线程池之后,它们就会由池中的线程来处理。当任务执行完毕之后,线程并不会被销毁,而是将它置于池中,等待下一个任务的到来。 线…

    多线程 2023年5月16日
    00
  • 详解进程同步与互斥机制

    详解进程同步与互斥机制 什么是进程同步和互斥? 在多进程环境下,多个进程之间共享计算机资源,例如共享内存区域。有时多个进程需要访问同一资源,这时候需要协调它们之间的访问,以免数据出现混乱。 进程同步是指协调多个进程之间的活动以达到一致的状态。进程互斥是指规范多个进程在不同时间访问资源的竞争环境,以防止它们同时访问同一资源而导致不可预测的后果。 进程同步的方法…

    多线程 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部