QT多线程编程(基础概念以及示例)

news2024/12/29 9:48:07

QT多线程编程

  • 前言:
  • 基础夯实:
    • 一:多线程概述
    • 二:QT多线程的使用
      • 1. 继承QThread类
      • 2. 继承QObject类
      • 3. QtConcurrent模块
    • 三:线程同步与通信
    • 四:线程安全
    • 五:线程管理
    • 六:总结
  • 效果展示:
  • 实现功能:
  • 核心代码:
    • mainwindow.h
    • mythread.h
    • mainwindow.cpp
    • main.cpp
    • mythread.cpp
  • 代码心得:
  • 仓库源码:

前言:

正好在做QT项目,感觉多线程编程很不错,虽然现在还没有用到,但是记录一下,和大家分享一下心得。

基础夯实:

一:多线程概述

多线程是指一个进程中包含至少两个执行流,即多个线程。每个线程都可以独立运行,访问该进程中的共享资源,并且可以与其它线程同步行动。多线程应用程序通常比单线程应用程序具有更好的响应速度和更好的资源利用率,适合于一些需要高效处理大量数据和执行复杂任务的场景。

二:QT多线程的使用

在QT中,使用QThread类可以方便地创建新的线程并在其中执行任务。以下介绍一些常用的QT多线程的技术和方法。

1. 继承QThread类

这是实现QT多线程的一种基本方式。主要步骤如下:

创建一个线程类的子类,继承Qt中的线程类QThread。
重写父类的run()方法,在函数内部编写子线程要处理的具体业务流程。run()方法是线程的入口点,类似于主线程中的main()函数。
在主线程中创建子类对象。
调用start()方法启动子线程。注意,不要直接调用run()方法,因为这会直接在主线程中执行,而不是在新的线程中。

2. 继承QObject类

另一种实现多线程的方式是继承QObject类,并通过moveToThread()方法将QObject对象移动到新创建的QThread中执行。主要步骤如下:

创建一个新的类,继承自QObject类。
在该类中添加公共的成员函数,函数体就是要在子线程中执行的业务逻辑。
在主线程中创建QThread对象和工作类对象。
将工作类对象移动到QThread对象中。
调用QThread对象的start()方法启动线程。
使用信号槽机制控制工作类对象的工作函数执行。

3. QtConcurrent模块

Qt还提供了QtConcurrent模块,这是一个在应用程序中创建并运行多个任务的高级方法。通过QtConcurrent::run()函数,可以方便地在后台线程中运行函数或Lambda表达式,而无需手动管理线程的生命周期。这种方式简化了多线程编程的复杂性,使得开发者可以更加专注于任务逻辑本身。

三:线程同步与通信

在多线程编程中,线程之间的同步和通信是非常重要的。QT提供了多种机制来实现这一点,包括互斥锁(QMutex)、读写锁(QReadWriteLock)、条件变量(QWaitCondition)以及信号槽机制等。

互斥锁(QMutex):用于保护共享资源,确保同一时间只有一个线程可以访问该资源。
读写锁(QReadWriteLock):允许多个线程同时读取共享资源,但写入时需要独占访问。
条件变量(QWaitCondition):用于线程之间的通信和同步,一个线程可以在某个条件不满足时等待,另一个线程在条件满足时通知等待的线程。
信号槽机制:Qt特有的跨线程通信机制,允许线程之间安全地发送信号和接收槽函数。

四:线程安全

在QT中,所有对UI的操作都必须放在主线程(GUI线程)中执行,因为QT的组件类和相关类只能工作在GUI线程。对于需要在工作线程中处理的数据或对象,需要确保线程安全,避免数据竞争和不一致的问题。

五:线程管理

在QT中,可以使用QThread类的各种函数来管理线程的生命周期,如start()、terminate()、wait()等。但需要注意的是,terminate()函数是强制终止线程的方法,可能会导致未定义的行为和数据损失,因此在实际开发中一般不建议使用。更推荐使用标志位和条件变量等机制来安全地终止线程。

六:总结

QT多线程编程是一个复杂但强大的功能,通过合理使用QThread类、QObject类以及QtConcurrent模块等工具和机制,可以实现高效、安全的多线程应用程序。开发者需要掌握线程的基本概念、QT多线程的使用方法、线程同步与通信机制以及线程安全和线程管理等方面的知识,才能充分发挥QT多线程编程的优势。

效果展示:

在这里插入图片描述

实现功能:

点击开始按钮,实现快速,冒泡,选择排序同时进行。

核心代码:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void starting(int num);

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QVector>
#include <QtGlobal>
#include <QDebug>
class Generate : public QThread
{
    Q_OBJECT
public:
    explicit Generate(QThread *parent = nullptr);

    void recvNum(int num);

protected:
    void run() override;

signals:
    void sendArray(QVector<int> num);

private:
    int m_num;

};

class BubbleSort : public QThread
{
    Q_OBJECT
public:
    explicit BubbleSort(QThread *parent = nullptr);

    void recvArray(QVector<int> list);

protected:
    void run() override;

signals:
    void Finish_Array(QVector<int> num);

private:
    QVector<int> m_list;

};
class SelectSort : public QThread
{
    Q_OBJECT
public:
    explicit SelectSort(QThread *parent = nullptr);

    void recvArray(QVector<int> list);

protected:
    void run() override;

signals:
    void Select_Array(QVector<int> num);

private:
    QVector<int> m_list;

};


class QuickSort : public QThread
{
    Q_OBJECT
public:
    explicit QuickSort(QThread *parent = nullptr);

    void recvArray(QVector<int> list);

protected:
    void run() override;
private:
    void quickSort(QVector<int> &list,int l ,int r);  //对list里起始位置l,结束位置r,进行排序

signals:
    void Finish_Array(QVector<int> num);

private:
    QVector<int> m_list;

};


#endif // MYTHREAD_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mythread.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //创建子线程对象
    Generate* generate = new Generate;
    BubbleSort* bubble_sort = new BubbleSort;
    QuickSort* quick_sort = new QuickSort;
    SelectSort* select_sort = new SelectSort;
    //启动子线程
    connect(this , &MainWindow::starting, generate , &Generate::recvNum);
    connect(ui->start, &QPushButton::clicked , this ,[=](){
        emit starting(10000);
        generate->start();
    });
    connect(generate,&Generate::sendArray,bubble_sort,&BubbleSort::recvArray);
    connect(generate,&Generate::sendArray,quick_sort,&QuickSort::recvArray);
    connect(generate,&Generate::sendArray,select_sort,&SelectSort::recvArray);
    //接受子线程发送的数据
    connect(generate , &Generate::sendArray , this , [=](QVector<int> list){
       bubble_sort->start();
       quick_sort->start();
       select_sort->start();
       for (int i=0;i<list.size();++i){
           ui->rand_list->addItem(QString::number(list.at(i)));
       }
    });
    connect(bubble_sort , &BubbleSort::Finish_Array , this , [=](QVector<int> list){
       for (int i=0;i<list.size();++i){
           ui->bubbel_list->addItem(QString::number(list.at(i)));
       }
    });
    connect(quick_sort , &QuickSort::Finish_Array , this , [=](QVector<int> list){
       for (int i=0;i<list.size();++i){
           ui->quick_list->addItem(QString::number(list.at(i)));
       }
    });
    connect(select_sort , &SelectSort::Select_Array , this , [=](QVector<int> list){
        for (int i=0;i<list.size();++i){
            ui->select_list->addItem(QString::number(list.at(i)));
        }
    });

}

MainWindow::~MainWindow()
{
    delete ui;
}

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mythread.cpp

#include "mythread.h"
#include <QElapsedTimer>  //计算执行时间的类
#include <QtGlobal>
#include <QMutex>

static QMutex g_mutex;  // 线程锁
Generate::Generate(QThread *parent)
    : QThread{parent}
{

}

void Generate::recvNum(int num)
{
    m_num = num;
}

void Generate::run()
{
    qDebug() <<"生成随机数的线程的地址:"<<QThread::currentThread();  //输出当前线程的地址
    QVector<int> list;
    QElapsedTimer time;
    time.start();
    for (int i=0;i<m_num;i++){
        list.push_back(rand() % 100000);
    }
    int milsec = time.elapsed();

    qDebug() <<"生成"<<m_num<<"个随机数总共用时"<<milsec<<"毫秒";
    emit sendArray(list);
}
//------------------------------------------------------------冒泡排序
BubbleSort::BubbleSort(QThread *parent) :QThread(parent)
{

}

void BubbleSort::recvArray(QVector<int> list)
{
    m_list = list;
}

void BubbleSort::run()
{
    g_mutex.lock();
    qDebug() <<"冒泡排序的线程的地址:"<<QThread::currentThread();  //输出当前线程的地址
    QElapsedTimer time;
    time.start();
    int temp;
    for (int i=0;i<m_list.size();++i){
        for(int j = 0;j<m_list.size()-i-1;++j){
            if(m_list[j]>m_list[j+1]){
                temp = m_list[j];
                m_list[j] = m_list[j+1];
                m_list[j+1] = temp;
            }
        }
    }
    int milsec = time.elapsed();

    qDebug() <<"冒泡排序总共用时"<<milsec<<"毫秒";
    emit Finish_Array(m_list);
    g_mutex.unlock();
}

//------------------------------------------------------------选择排序
SelectSort::SelectSort(QThread *parent) :QThread(parent)
{

}

void SelectSort::recvArray(QVector<int> list)
{
    m_list = list;
}

void SelectSort::run()
{
    g_mutex.lock();
    qDebug() <<"选择排序的线程的地址:"<<QThread::currentThread();  //输出当前线程的地址
    QElapsedTimer time;
    time.start();
    int temp;
    for (int i = 0; i < m_list.size() - 1; ++i) {
        // 假设当前元素为最小值
        int minIndex = i;
        // 从当前元素的下一个位置开始寻找更小的元素
        for (int j = i + 1; j < m_list.size(); ++j) {
            if (m_list[j] < m_list[minIndex]) {
                minIndex = j;
            }
        }
        // 如果找到更小的元素,则交换它们
        if (minIndex != i) {
            std::swap(m_list[i], m_list[minIndex]);
        }
    }
    int milsec = time.elapsed();
    qDebug() <<"选择排序总共用时"<<milsec<<"毫秒";
    emit Select_Array(m_list);
    g_mutex.unlock();
}
//------------------------------------------------------------快速排序
void QuickSort::quickSort(QVector<int> &s, int l, int r) {
    if (l >= r) return;  // 递归结束条件
    int pivot = s[l];  // 基准元素
    int i = l, j = r;
    while (i < j) {
        while (i < j && s[j] >= pivot) j--;
        if (i < j) s[i++] = s[j];
        while (i < j && s[i] <= pivot) i++;
        if (i < j) s[j--] = s[i];
    }
    s[i] = pivot;
    quickSort(s, l, i - 1);  // 对左边子序列进行快速排序
    quickSort(s, i + 1, r);  // 对右边子序列进行快速排序
}

QuickSort::QuickSort(QThread *parent):QThread(parent)
{

}

void QuickSort::recvArray(QVector<int> list)
{
    m_list = list;
}

void QuickSort::run()
{
    qDebug() <<"快速排序的线程的地址:"<<QThread::currentThread();  //输出当前线程的地址
    QElapsedTimer time;
    time.start();

    quickSort(m_list,0,m_list.size()-1);

    int milsec = time.elapsed();

    qDebug() <<"快速排序总共用时"<<milsec<<"毫秒";
    emit Finish_Array(m_list);
}

代码心得:

代码可以简单分为四个模块,第一个模块产生随机数填充在列表项。其他三个模块分别是快速排序,冒泡排序,选择排序的算法,并将其结果显示在折叠列表项里面。四个类大同小异,这四个类包含的主要函数有三个,接受数据,处理数据,发送数据。在窗口函数中,实现四个线程的创建,然后启动,进行处理。

仓库源码:

需要看ui文件的,点击查看源码:gitee仓库源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2134473.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024数学建模国赛官方评阅标准发布!

​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑…

被百度 AI 文心一言推荐的 Mac App 惊喜到了!

由于工作需要&#xff0c;我需要一款 Mac 软件帮我记录所有的复制记录。 当我去百度搜索“mac 复制记录”“mac 复制历史”时&#xff0c;百度 AI 给我推荐了这三款 App&#xff1a;Maccy、CleanClip、Collect Boy。 我开始分别试用这三款软件&#xff0c;我现在还没全部试用完…

002集—— CAD划线并模拟向命令窗口发送命令(CAD—C#二次开发入门)

模拟向命令窗口发送全图居中的命令&#xff1a; Application.DocumentManager.MdiActiveDocument.SendStringToExecute("z\ne\n",true,false,false); 弹窗命令&#xff1a; Application.ShowAlertDialog("Erase the newly added polyline."); 本例在ca…

macos清理垃圾桶时提示 “操作无法完成,因为该项目正在使用中” 解决方法 , 强制清理mac废纸篓 方法

在macos中&#xff0c;删除文件后&#xff0c; 在清理垃圾桶时提示 “操作无法完成&#xff0c;因为该项目正在使用中” 出现这个提示&#xff0c;在大多数的情况下是因为数据问题导致&#xff0c;需要通过磁盘管理工具进行修复&#xff0c;修复后才可彻底的清理垃圾桶。 另外…

FPGA低功耗设计

FPGA低功耗设计 文章目录 FPGA低功耗设计前言一、功耗类型1.1 动态功耗1.2 静态功耗1.3 浪涌功耗 二、系统级低功耗设计2.1 **多电压技术&#xff1a;**即工作频率、电压和功耗的关系2.2 系统时钟分配&#xff1a;2.3 软硬件划分2.4 p 或单元库选择 三、RTL级别低功耗设计3.1 并…

运算放大电路

填鸭子呢 兴趣没了&#xff0c;啥也没了 运行过程&#xff0c;少了什么 差分放大 二极放大 功率放大 输出为饱和 反馈调整放大 倍数 考试 我可以认为就应该那样 但理解却不能如 懂了不妨碍我不会用 会用不妨碍我不懂 也想设计一个如哆来A梦那样的&#xff1b; 什么…

Gapless-REMA100:一个通过多源DEM填补空白的南极洲无缝100米参考高程模型

ABSTRACT 南极洲的数字高程模型&#xff08;DEM&#xff09;是冰川学应用中至关重要的数据集&#xff0c;广泛用于从野外工作规划到冰盖动力学分析等多个方面。高空间分辨率的DEM数据能够更详细地描绘地形。南极洲参考高程模型&#xff08;REMA&#xff09;马赛克是最近发布的…

VR全景视频编辑SDK解决方案,指尖玩转全景世界

随着虚拟现实&#xff08;VR&#xff09;技术的日益成熟&#xff0c;全景视频以其沉浸式、全方位的视觉体验&#xff0c;成为了连接现实与虚拟世界的桥梁。然而&#xff0c;传统VR视频编辑的繁琐流程和高门槛&#xff0c;往往限制了创作者们的灵感释放与作品传播。如今&#xf…

我的独立游戏-休闲社交游戏-“淘金城堡“CSDN上线了

大家好&#xff0c;我的休闲社交游戏-"淘金城堡"在CSDN课堂上线了&#xff0c;有91节视频课和三个开发阶段的项目源码&#xff0c;非常适合分阶段学习。 项目的地址&#xff1a; http://t.csdnimg.cn/m0hFd 游戏截图 这个项目是我开发的一款独立游戏的附属产物。 …

【信道复用技术】

信道复用技术 复用&#xff08;multiplexing&#xff09;是通信技术种的基本概念。它允许用户使用一个共享信道进行通信&#xff0c;降低成本&#xff0c;提高利用率。 如下图所示&#xff0c;情况a是A1&#xff0c;B1&#xff0c;C1各自使用自己单独的信道&#xff0c;情况b…

苹果CMS与海洋CMS安全性对比:为什么苹果CMS更值得信赖

苹果CMS&#xff08;Maccms&#xff09;介绍及安全性分析 在选择内容管理系统&#xff08;CMS&#xff09;时&#xff0c;安全性是每个网站管理员都必须重点考虑的因素。苹果CMS&#xff08;maccmscn&#xff09;和海洋CMS都是在国内较受欢迎的CMS平台&#xff0c;但它们在安全…

在WordPress中最佳Elementor主题推荐:进阶级指南

如果你已经熟悉WordPress和Elementor&#xff0c;选择功能更强大、定制性更高的主题能进一步提升网站质量。今天&#xff0c;我为大家介绍五款适合用户的进阶级Elementor主题&#xff1a;Shoptimizer、OceanWP、Hestia、Zakra和Phlox。这些主题不仅功能丰富&#xff0c;而且非常…

Maven私服Nexus安装及使用

前言 周末在家闲着无聊&#xff0c;不知道做点啥&#xff0c;就想着自己搭建一个Maven私服来玩玩。刚好使用自己之前在电脑上搭建的虚拟机服务器来操作体验了一把。搭建好私服后&#xff0c;以后自己写的一些小模块啊&#xff0c;工具包啥的就可以发布到自己的私服上了&#xf…

【信创】推荐一款好用的免费在线流程图思维导图工具 _ 统信 _ 麒麟 _ 方德

原文链接&#xff1a;【信创】推荐一款好用的免费在线流程图思维导图工具 | 统信 | 麒麟 | 方德 Hello&#xff0c;大家好啊&#xff01;今天给大家推荐一款非常好用的免费在线流程图和思维导图工具——ProcessOn。无论是项目管理、数据分析、头脑风暴还是日常办公&#xff0c;…

常见的弹性公网ip类型

常见的弹性公网ip类型有常规BGPIP、精品BGPIP、加速IP、静态单线IP、高防EIP。弹性公网ip的优点在于灵活、稳定、安全和可扩展等方面&#xff0c;适用于不同的业务场景和需求&#xff0c;用户可以根据自身的实际情况进行选择。以下是对常见的弹性公网ip类型的具体分析&#xff…

使用 PyCharm 新建 Python 项目详解

使用 PyCharm 新建 Python 项目详解 文章目录 使用 PyCharm 新建 Python 项目详解一 新建 Python 项目二 配置环境1 项目存放目录2 Python Interpreter 选择3 创建隔离环境4 选择你的 Python 版本5 选择 Conda executable 三 New Window 打开项目四 目录结构五 程序编写运行六 …

ADS1248 测电阻 0~10欧姆

目录 需求 端口供电范围 PGA 振荡器 恒流源IDAC 配置 需求 测量范围0~10欧姆&#xff1b; 误差&#xff1a;0.01欧姆 端口供电范围 注意的端口Vref 最小电压0.5V &#xff1b; PGA 振荡器 恒流源IDAC 配置 恒流源通过电阻提供基准&#xff1b; 恒流源1mA&#xff0c…

k8s的搭建

一、安装环境 准备三台主机&#xff1a; 192.168.1.66 k8s-master 192.168.1.77 k8s-node01 192.168.1.88 k8s-node02 网段&#xff1a; Pod ⽹段 172.16.0.0/16 Service ⽹段 10.96.0.0/16 注&#xff1a;宿主机⽹段、Pod…

集群聊天服务器项目【C++】项目介绍和环境搭建

前言&#xff1a;学习一个基于C集群聊天服务器的项目&#xff0c;记录学习的内容和学习的过程。 1.项目介绍 在 Linux 环境下基于 muduo 开发的集群聊天服务器。实现新用户注册、用户登录、添加好友、添加群组、好友通信、群组聊天、保持离线消息等功能。 2.技术栈 Json序列…

CSS基本布局理解(测试)——WEB开发系列38

对CSS学习已经接近尾声&#xff0c;下面你可以对以下两道“小卡拉米”测试进行测试下CSS理解程度。 题 1&#xff1a;基于栅格布局的现代博客首页设计 题目要求&#xff1a; 创建一个博客首页布局&#xff0c;包含一个顶部导航栏、一个主要的内容区域&#xff08;左侧为博客文…