## 今天学了什么
今天学习Qt中的多线程以及利用多线程实现随机数排序案例。
## 多线程
定义:一个进程内,同时运行多个执行流(线程),共享进程资源,各自并发执行。
作用:
- 耗时任务放子线程,避免UI卡死;
- 多个任务并行执行,提升运行速度;
多线程与多进程区别:
- 多线程:同一程序里同时做多件事,防止界面卡住,提升效率。
- 多进程:多个独立程序分开跑,一个崩了不影响另一个。
Qt创建线程方式:
① 继承QThread,重写run()(可控性最强);
② QObject + moveToThread(业务对象和线程分离);
③ QThreadPool + QRunnable(线程池,复用线程,适合大量短任务);
④ QtConcurrent::run(简易并发,高层简化接口,底层依赖线程池,适合简单一次性任务);// 高层封装,底层线程池 暂时了解
注:①②自己创建,管理线程;③④只提交任务,线程由线程池调度;
### 通过继承QThread类实现随机数排序
要求:点击开始按钮,生成自定义个数的随机数,并进行冒泡排序和快速排序。
实现:
① 创建继承子类:
#include "mythread.h"
Generate::Generate(QObject *parent)
: QThread{parent}
{}
void Generate::getnum(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(QRandomGenerator::global()->bounded(100001));
}
int m=time.elapsed();
qDebug()<<"生成"<<m_num<<" 个随机数,耗时:"<<m<<" 毫秒。";
emit finish(list);
}
Bubble::Bubble(QObject *parent)
: QThread{parent}
{}
void Bubble::getnum(QVector<int> num)
{
m_list=num;
}
void Bubble::run()
{
qDebug()<<"冒泡排序线程地址:"<<QThread::currentThread();
QElapsedTimer time;
time.start();
int num=m_list.size();
for(int i=0;i<num;i++)
{
for(int j=0;j<num-i-1;j++)
{
if(m_list[j]>m_list[j+1])
{
int temp=m_list[j];
m_list[j]=m_list[j+1];
m_list[j+1]=temp;
}
}
}
int m=time.elapsed();
qDebug()<<"冒泡排序完成,耗时:"<<m<<" 毫秒。";
emit finish(m_list);
}
Quick::Quick(QObject *parent)
: QThread{parent}
{}
void Quick::getnum(QVector<int> num)
{
m_list=num;
}
void Quick::run()
{
qDebug()<<"快速排序线程地址:"<<QThread::currentThread();
QElapsedTimer time;
time.start();
quickscore(m_list,0,m_list.size()-1);
int m=time.elapsed();
qDebug()<<"快速排序完成,耗时:"<<m<<" 毫秒。";
//qDebug()<<"快排结果"<<m_list;
emit finish(m_list);
}
void Quick::quickscore(QVector<int> &num,int l,int r)
{
if(l<r)
{
int i=l;
int j=r;
int x=num[l];
while(i<j)
{
//从右往左比较 找比x 小的
while(i<j&&num[j]>x) j–;
if(i<j)
{
num[i++]=num[j];//m_list[i]=m_list[j];i++;
}
//从左往右比较 找比x 大的
while(i<j&& num[i]<x) i++;
if(i<j)
{
num[j–]= num[i];//m_list[j]=m_list[i];j–;
}
}
num[i]=x;
quickscore(num,l,i-1);
quickscore(num,i+1,r);
}
}
② 主窗口构造:
#include "widget.h"
#include "./ui_widget.h"
#include "mythread.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
Generate *gen=new Generate;
Bubble *bubble=new Bubble;
Quick *quick=new Quick;
//设置随机数个数
connect(this,&Widget::starting,gen,&Generate::getnum);
//连接按钮和gen
connect(ui->btn,&QPushButton::clicked,gen,[=](){
emit starting(3000);
gen->start();
});
//连接gen 和 bubble
connect(gen,&Generate::finish,bubble,&Bubble::getnum);
//连接gen 和 quick
connect(gen,&Generate::finish,quick,&Quick::getnum);
//连接gen 和 主窗口 返回随机好的内容
connect(gen,&Generate::finish,[=](QVector<int> list){
bubble->start();
quick->start();
for(auto s:list)
{
ui->randWidget->addItem(QString::number(s));
}
});
//连接bubble 和 主窗口 返回排序好的内容
connect(bubble,&Bubble::finish,this,[=](QVector<int> list){
for(auto s:list)
{
ui->bubbleWidget->addItem(QString::number(s));
}
});
//连接qucik 和 主窗口 返回排序好的内容
connect(quick,&Quick::finish,this,[=](QVector<int> list){
for(auto s:list)
{
ui->quickWidget->addItem(QString::number(s));
}
});
connect(this,&Widget::destroyed,[=](){
gen->quit();
gen->wait();
gen->deleteLater();
bubble->quit();
bubble->wait();
bubble->deleteLater();
quick->quit();
quick->wait();
quick->deleteLater();
});
}
Widget::~Widget()
{
delete ui;
}
问题复盘:
① 排序对象执行start()之前一定要先赋值getnum(),不然存在风险,不稳定,可能出错;
② new 出来的对象一定要释放,防止内存泄漏,释放步骤quit-wait-delete;
③ 在写快速排序时,注意int x=num[l] 位置,不能放在if外面,会报错;在递归调用前,必须让基准元素("x")归位(num[i]=x);
④ 生成随机数还可以用qrand()%100;
⑤ 隐藏问题,Qt不保证槽的执行顺序,gen的finish 连接三个槽函数,虽然赋值函数位置写在start()前面,但运行时可能出现先start()再赋值的情况,导致错误,最好将赋值和start()写在同一个lambda里,并且赋值写在start之前。
![[LangChain] 学习笔记(02):LCEL 链式调用与动态模型配置实战-171主机测评](https://www.171host.com/wp-content/uploads/2026/10/20261030203301-6ae4fefdb54f3-220x150.png)
![[LangChain] 学习笔记(02):LCEL 链式调用与动态模型配置实战-171主机测评](https://www.171host.com/wp-content/uploads/2026/10/20261030202745-6ae4fdc1556bf-220x150.png)

