欢迎光临
我们一直在努力

Qt学习日记 Day10:多线程(一)+随机数排序案例

## 今天学了什么

今天学习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之前。

赞(0)
未经允许不得转载:171主机测评 » Qt学习日记 Day10:多线程(一)+随机数排序案例
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址