Qthread应用

前言

重新学习qthread,有一个任务,我们要交给子线程运行,把结果传到主线程,那我们只需要将任务类继承Qthread,重写run函数,在里面写运行逻辑,当主线程需要它运行的时候就会触发start开始子线程,这就是多线程的核心思想。

这里我设计了一个程序,有三个部分,第一个部分lsw1是一个listwidget,显示生成的随机数,第二个显示冒泡排序的结果,第三个生成快速排序的结果,ui如下:

界面搭建就不用讲了,接下来讲讲功能的实现。

为什么采用多线程

大家都知道采用多线程的时候程序运行快,界面不容易出现卡顿,当数据量大的时候,如果在主线程里面执行,他会阻塞主线程的ui刷新造成卡顿现象,就需要把这些事务处理放到子线程里面,主线程只负责ui的更新。

随机数生成

经过上面的讲述,我们随机数生成可以放在一个专门的线程,类命名为Generat,继承Qthread,除了需要重写run函数,我们需要从主线程接受需要生成多少个随机数这样的一个函数

复制代码
//将主线程中接受的数据赋值给m_num
    void recnum(int num);

m_num是这个类的成员函数,还需要在我们排序执行完了以后,需要有一个信号,把执行结果传递给主线程,他们之间用connect的Qt::QueuedConnection模式进行通讯 ,和运行了多久的计时器时间也要通过信号传递

复制代码
//生成的序列发送信号
    void sendarray(QVector<int> num);
    //发送用时
    void sendtime(int time);

计时器的选用

计时器采用的是QElapsedTimer类,这是一个毫秒级的计时器,当程序运行过快的时候,会出现一个问题,比如运行时间只有1ms,太小了,他就会为0,碰到这种情况有两个解决办法

1.增加数据量,延长程序的运行时间

2.采用精度更高的计时器

run函数实现

随机数刷新用到了QRandomGenerator类,先上我使用的方法

复制代码
for (int i = 0; i < m_num; ++i) {
        list.push_back(QRandomGenerator::global()->bounded(0,10000));
    }

该类下global是一个随机数生成器,bounded限制他的生成范围,第一个参数是最小值,第二个参数是最大值。

类整体展示

cpp 复制代码
//mytread.h
//生成随机数的线程类
class Generate:public QThread
{
    Q_OBJECT
public:
    Generate(QObject *parent=nullptr);

    //将主线程中接受的数据赋值给m_num
    void recnum(int num);
    // QThread interface
private:
    int m_num;

protected:
    void run() override;

signals:
    //生成的序列发送信号
    void sendarray(QVector<int> num);
    //发送用时
    void sendtime(int time);
    //随机数生成完毕,通知排序工作线程开始工作
    void startsort();
};
cpp 复制代码
//mythread.cpp
void Generate::recnum(int num)
{
    m_num=num;
}

//生成随机数线程
void Generate::run()
{
    QVector<int>list;
    QElapsedTimer timer;
    timer.start();
    for (int i = 0; i < m_num; ++i) {
        list.push_back(QRandomGenerator::global()->bounded(0,10000));
    }
    int milsec=timer.elapsed();
    emit sendarray(list);
    emit sendtime(milsec);
    emit startsort();
}

有一个信号是后面加的start sort,在他的下一级还有两个工作线程,他相当于是个生产者,生产好了以后通知消费者开始用这些数据工作。

这样线程类就做好了,在主程序中做好connect接收子线程的信号传递的数据,在ui上显示就行了。

信号的处理绑定

主线程中首先把子线程类的对象new出来

cpp 复制代码
Generate *gen=new Generate;

主程序有一个starting信号,负责把生成多少个随机数发送给子线程,子线程的recnum函数就会接收处理,当界面的按钮点击了以后,就会发送starting信号,并启动随机数线程

cpp 复制代码
//通过信号将要创建多少个随机数传递给子线程
    connect(this,&MainWindow::starting,gen,&Generate::recnum,Qt::QueuedConnection);

    //点击按钮后执行子线程
    connect(ui->pushButton,&QPushButton::clicked,this,[=](){
        emit starting(10000);
        gen->start();
    });

冒泡排序线程

线程的设计和上面差不多,不过他没有下级线程要通知,随机数线程生成了随机数数组后会有个信号传递数组,我们冒泡的线程也接收一份,进行排序逻辑处理

cpp 复制代码
void Bubblesort::run()
{
    QElapsedTimer time;//采用秒级计时器,如果数据太少执行太快会导致运行时间太短显示运行0秒
    time.start();
    int temp;
    //升序冒泡
    for (int i = 0; i < m_num.size(); ++i) {
        for (int j = 0; j < m_num.size()-i-1; ++j) {
            if(m_num.at(j)>m_num.at(j+1)){
                temp=m_num.at(j);
                m_num[j]=m_num[j+1];
                m_num[j+1]=temp;
            }
        }
    }
    int sec=time.elapsed();
    emit sendarray(m_num);//发送排序后的数组
    emit sendtime(sec);//发送时间
}

快速排序线程

同上,逻辑:

cpp 复制代码
//快速排序实现
void Quicksort::quicksort(QVector<int> &arr, int left, int right)
{
    if (left >= right) return;

    int i = left;
    int j = right;
    // 取中间值作为基准,避免最坏情况
    int pivot = arr[(left + right) / 2];

    while (i <= j) {
        while (arr[i] < pivot) i++;  // 找左边大于等于基准的
        while (arr[j] > pivot) j--;  // 找右边小于等于基准的

        if (i <= j) {
            // 交换元素
            std::swap(arr[i], arr[j]);
            i++;
            j--;
        }
    }

    // 递归排序子数组
    quicksort(arr, left, j);
    quicksort(arr, i, right);
}

void Quicksort::run()
{
    QElapsedTimer time;
    time.start();
    quicksort(m_num,0,m_num.size()-1);
    int sec=time.elapsed();
    emit sendarray(m_num);//发送数组
    emit sendtime(sec);//发送时间
}

效果

剩余的就是在主线程做一些信号绑定就行了,运行效果如下:

由此看到,当遇到数据量比较大的时候,冒泡排序是非常慢的,如果放到主线程跑,ui这段时间内都废了,十分影响使用体验。

相关推荐
武当豆豆1 小时前
C++编程学习阶段性总结
开发语言·c++
赟赟、嵌入式2 小时前
imx6ul Qt运行qml报错This plugin does not support createPlatformOpenGLContext!
开发语言·qt
A7bert7773 小时前
【YOLOv8-obb部署至RK3588】模型训练→转换RKNN→开发板部署
linux·c++·人工智能·python·yolo
zyx没烦恼4 小时前
五种IO模型
开发语言·c++
EutoCool4 小时前
Qt窗口:菜单栏
开发语言·c++·嵌入式硬件·qt·前端框架
圆头猫爹7 小时前
第34次CCF-CSP认证第4题,货物调度
c++·算法·动态规划
十五年专注C++开发7 小时前
hiredis: 一个轻量级、高性能的 C 语言 Redis 客户端库
开发语言·数据库·c++·redis·缓存
hi0_67 小时前
03 数组 VS 链表
java·数据结构·c++·笔记·算法·链表
碧海蓝天20228 小时前
C++法则21:避免将#include放在命名空间内部。
开发语言·c++
CodeWithMe8 小时前
【读书笔记】《C++ Software Design》第一章《The Art of Software Design》
开发语言·c++