一、 线程类 QThread
方法1:
(1)需要创建一个线程类的子类,让其继承QT中的线程类 QThread。
(2)重写父类的 run() 方法,在该函数内部编写子线程,要处理的具体的任务,并通过信号函数,把完成的结果发生到主线程。
(3)在主线程中,创建子线程对象,通过new方式创建,注意不用写(this)。
(4)通过主线程的信号(按钮点击),启动子线程, 调用 start() 方法。
(5)当子线程创建出来之后,主线程与子线程之间的通信可以通过信号槽的方式,通过主线程的信号函数,传递子线程需要的数据(产生随机数的数量)。
(6)此时,子线程会执行run()函数完成具体任务(生成一定数量的随机数)。
(7)通过信号槽方式,在主线程显示,接受的子线程发送的随机数结果。(显示界面只能在主线程操作,子线程不能直接操作)
(8)运行完成,释放线程资源。
示例代码
1.子线程 生成 随机数,通过 重写子线程虚函数,用来生成随机数、放置随机数、并发送到主线程
1.1 编写生成 随机数的类(头文件、源文件)
1.2 重写 子线程虚函数,用来生成随机数,然后,QVector<int> list 放置随机数 数组
1.3 触发 信号函数 发送子线程生成的随机数
//头文件
#include <QThread> //线程类头文件
#include <QVector> //动态数组容器类
//1.生产随机数
class Generate : public QThread
{
Q_OBJECT
public:
explicit Generate(QObject *parent = nullptr);
void recvNum(int num); //接收 外部需要产生随机数的数量num, 传递给m_num
//2.重写子线程虚函数
protected:
void run() override;
signals:
//3.触发 信号函数 发送子线程生成的随机数 数组
void sendArray(QVector<int> num);
private:
int m_num; //产生随机数 数量
};
//源文件
#include "mythread.h"
#include <QElapsedTimer> //计时工具,用于测量代码执行时间和延迟时间
#include <QDebug>
Generate::Generate(QObject *parent) : QThread(parent)
{
}
void Generate::recvNum(int num) //接收 外部需要产生随机数的数量num, 传递给m_num
{
m_num = num;
}
void Generate::run() //重写虚函数 子线程生成的随机数数组发生给主线程
{
qDebug()<<"生成随机数ID"<<QThread::currentThread(); //获取当前执行线程的ID
QVector<int> list; //创建一个数组,放置随机数
QElapsedTimer time; //创建一个time,记录生成m_num个随机数 代码执行的时间
time.start(); //启动计时器
for(int i = 0; i < m_num; ++i)
{
//qrand() %100000 生成100000以内的随机数
list.push_back(qrand() %100000); //push_back 在数组末尾添加一个元素
}
int milsec = time.elapsed();//代码执行的时间 ms
qDebug()<<"生成"<<m_num<<"随机数总共耗时:"<<milsec<<"ms";
//触发 发送生成的随机数数组 到主线程
emit sendArray(list);
}
2. 主线程
2.1 创建子线程对象
2.2 主线程 将 需要生成的随机数 数量 传递给子线程对象的槽函数
2.3 启动子线程 ,子线程会执行run()函数完成具体任务(生成一定数量的随机数)
2.4 通过信号槽函数 ,主线程 接受 子线程发送的随机数数组 显示出来
//头文件
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
signals:
void starting(int num);
private:
Ui::Widget *ui;
};
//源文件
#include "widget.h"
#include "ui_widget.h"
#include "mythread.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//1.创建子线程对象
Generate *gen = new Generate;
//主线程 将 需要生成的随机数数量 传递给子线程对象的槽函数
connect(this,&Widget::starting,gen,&Generate::recvNum);
//2.启动子线程
connect(ui->start,&QPushButton::clicked,this,[=]()
{
emit starting(10000); //主线程需要生成 10000个随机数传递出去
gen->start();
});
//3.接受 子线程发送的随机数 在主线程 打印出来
connect(gen,&Generate::sendArray,this,[=](QVector<int> list)
{
for(int i=0; i<list.size(); ++i)
{
ui->randList->addItem(QString::number(list.at(i))); //将数字转换为QString类型
}
});
}
Widget::~Widget()
{
delete ui;
}
3. 子线程 冒泡排序(快速排序与冒泡排序类似), 重复上述1-2步骤,:
3.1 通过重写 子线程虚函数run,用来对随机数数组进行 ,并将排序结果,通过 emit 发送到主线程。
//头文件
//1.冒泡排序
class BubbleSort : public QThread
{
Q_OBJECT
public:
explicit BubbleSort(QObject *parent = nullptr);
void recvArray(QVector<int> list);
//2.重写子线程虚函数
protected:
void run() override;
signals:
//3.触发 信号函数 发送子线程生成的冒泡排序数组 到主线程
void finish(QVector<int> num);
private:
//需要排序的对象
QVector<int> m_list;
};
//源文件
void BubbleSort::run()
{
// 日志的 输出
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(m_list);
}
3.2 在主线程中,创建子线程对象,启动子线程(在子线程生成随机数之后), 通过信号槽函数,随机数对象信号函数(发送随机数数组),冒泡排序对象接收随机数数组。
3.3 通过信号槽函数 ,主线程 接受 子线程发送的冒泡排序结果 显示出来 。
//1.创建子线程对象
BubbleSort* bubble =new BubbleSort;
QuickSort* quick =new QuickSort;
//3.接收来自gen.sendArray 传来的数组,到冒泡排序类
connect(gen,&Generate::sendArray,bubble,&BubbleSort::recvArray);
//3.接收来自gen.sendArray 传来的数组,到快速排序类
connect(gen,&Generate::sendArray,quick,&QuickSort::recvArray);
//2.接受 子线程发送的随机数 在主线程 打印出来
connect(gen,&Generate::sendArray,this,[=](QVector<int> list)
{
//此时,随机数数组已经生成完毕,启动,bubble、quick子线程
bubble->start();
quick->start();
for(int i=0; i<list.size(); ++i)
{
ui->randList->addItem(QString::number(list.at(i))); //将数字转换为QString类型
}
});
//4.接收数组,进行冒泡排序,并显示在框内
connect(bubble,&BubbleSort::finish,this,[=](QVector<int> list)
{
for (int i = 0;i<list.size() ; ++i )
{
ui->bubbleList->addItem(QString::number(list.at(i)));
}
});
//7.接收数组,进行快速排序,并显示在框内
connect(quick,&QuickSort::finish,this,[=](QVector<int> list)
{
for (int i = 0;i<list.size() ; ++i )
{
ui->quickList->addItem(QString::number(list.at(i)));
}
});
3.4 线程资源释放。
//8.线程资源释放
connect(this,&Widget::destroyed,this,[=]()
{
gen->quit();
gen->wait();
gen->deleteLater(); //delete t1
bubble->quit();
bubble->wait();
bubble->deleteLater();
quick->quit();
quick->wait();
quick->deleteLater();
});
快速排序代码段:
//快速排序
void quickSort(QVector<int> &s,int l,int r)
{
if(l >= r) return;
int i=l-1,j=r+1,x=s[l + r >> 1];
while(i<j)
{
do i++;while(s[i]<x);
do j--;while(s[j]>x);
if(i<j)
{
int temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
quickSort(s,l,j);
quickSort(s,j+1,r);
}