# Qt 多线程

# 1, 构造函数

// 构造函数
QThread::QThread(QObject *parent = Q_NULLPTR);
// 判断线程中的任务是不是处理完毕了
bool QThread::isFinished() const;
// 判断子线程是不是在执行任务
bool QThread::isRunning() const;
// Qt 中的线程可以设置优先级
// 得到当前线程的优先级
Priority QThread::priority() const;
void QThread::setPriority(Priority priority);
优先级:
    QThread::IdlePriority         --> 最低的优先级
    QThread::LowestPriority
    QThread::LowPriority
    QThread::NormalPriority
    QThread::HighPriority
    QThread::HighestPriority
    QThread::TimeCriticalPriority --> 最高的优先级
    QThread::InheritPriority      --> 子线程和其父线程的优先级相同, 默认是这个
// 退出线程,停止底层的事件循环
// 退出线程的工作函数
oid QThread::exit(int returnCode = 0);
// 调用线程退出函数之后,线程不会马上退出因为当前任务有可能还没有完成,调回用这个函数是
// 等待任务完成,然后退出线程,一般情况下会在 exit () 后边调用这个函数
bool QThread::wait(unsigned long time = ULONG_MAX);

# 信号槽

// 和调用 exit () 效果是一样的
[slot] void QThread::quit();
// 启动子线程
[slot] void QThread::start(Priority priority = InheritPriority);
// 线程中执行的任务完成了,发出该信号
// 任务函数中的处理逻辑执行完毕了
[signal] void QThread::finished();
// 开始工作之前发出这个信号,一般不使用
[signal] void QThread::started();

# 静态函数

// 返回一个指向管理当前执行线程的 QThread 的指针
[static] QThread *QThread::currentThread();
// 返回可以在系统上运行的理想线程数 == 和当前电脑的 CPU 核心数相同
[static] int QThread::idealThreadCount();
// 线程休眠函数
[static] void QThread::msleep(unsigned long msecs);	// 单位:毫秒
[static] void QThread::sleep(unsigned long secs);	// 单位:秒
[static] void QThread::usleep(unsigned long usecs);	// 单位:微秒

# 任务处理

// 子线程要处理什么任务,需要写到 run () 中
[virtual protected] void QThread::run();

# 2, 任务对象移动到主线程

# 线程头文件

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
#include <QVector>
// 创建的子线程,生成随机数
class Generate : public QObject
{
    Q_OBJECT
public:
    explicit Generate(QObject *parent = nullptr);
    // 接受主线程传过来的参数,随机数 num
    // 子线程运行函数,第二种方法可以直接将 num 作为参数传入
    void working(int num);
signals:
    // 使用信号槽将数据传递给主线程,界面操作只能由主线程来进行
    void sendArray(QVector<int> num);
public slots:
};
// 冒泡排序
class BubbleSort : public QObject
{
    Q_OBJECT
public:
    explicit BubbleSort(QObject *parent = nullptr);
    // 子线程运行函数
    void working(QVector<int> list);
signals:
    // 使用信号槽将数据传递给主线程,界面操作只能由主线程来进行
    // 发送的有序数组
    void finish(QVector<int> list);
public slots:
};
// 快速排序
class QuickSort : public QObject
{
    Q_OBJECT
public:
    explicit QuickSort(QObject *parent = nullptr);
    // 子线程运行函数
    void working(QVector<int> list);
signals:
    // 使用信号槽将数据传递给主线程,界面操作只能由主线程来进行
    void finish(QVector<int> list);
public slots:
private:
    // 实现快速排序算法
    // 容器,起始位置,结束位置
    void quickSort(QVector<int> &list,int l,int r);
};
#endif // MYTHREAD_H

# 线程实现

#include "mythread.h"
#include <QElapsedTimer>  // 记录时间
#include <QtDebug>
#include <QThread>
Generate::Generate(QObject *parent) : QObject(parent)
{
}
void Generate::working(int num)
{
    qDebug()<< "生成随机数的线程地址" <<QThread::currentThread();
    // 存放随机数 vector 容器
    QVector<int> list;  // 子线程生成数据,要通过传递给主线程
    QElapsedTimer time;
    time.start();// 开始记录
    for (int i = 0;i <num;++i)
    {
        // 从尾部插入
        list.push_back(qrand()%100000);
    }
    qint64 milsec = time.elapsed(); // 毫秒
    qDebug()<< "生成" <<num << "个随机总数用时"<<milsec<<"毫秒";
    // 发送给主线程
    emit sendArray(list); // 将数据发给主线程
}
// 冒泡排序,补齐 parent
BubbleSort::BubbleSort(QObject *parent) : QObject(parent)
{
}
// 实现冒泡排序,实现相邻两个元素的交换
void BubbleSort::working(QVector<int> list)
{
    qDebug()<< "冒泡排序的线程地址" <<QThread::currentThread();
    // 存放随机数 vector 容器
    QElapsedTimer time;
    time.start();
    int temp;
    for(int i = 0;i<list.size();++i)
    {
        for(int j =0;j<list.size()-i-1;++j) // 从后数往前比较
        {
            if(list[j]>list[j+1])
            {
                temp = list[j];
                list[j] = list[j+1];
                list[j+1]=temp;
            }
        }
    }
    qint64 milsec = time.elapsed();
    qDebug()<< "冒泡排序用时" <<milsec<<"毫秒";
    // 发送给主线程
    emit finish(list); // 将数据发给主线程
}
// 快速,补齐 parent
QuickSort::QuickSort(QObject *parent) : QObject(parent)
{
}
// 实现快速排序
void QuickSort::working(QVector<int> list)
{
    qDebug()<< "快速排序的线程地址" <<QThread::currentThread();
    // 存放随机数 vector 容器
    QElapsedTimer time;
    time.start();
    // 快速排序算法
    quickSort(list,0,list.size()-1);
    qint64 milsec = time.elapsed();
    qDebug()<< "快速排序用时" <<milsec<<"毫秒";
    // 发送给主线程
    emit finish(list); // 将数据发给主线程
}
// 快排算法
void QuickSort::quickSort(QVector<int> &s, int l, int r)
{
    if(l < r)
    {
        int i = l,j=r;
        // 拿出第一个元素,保存到 x 中,第一个位置为空
        int x = s[l];
        while (i < j)
        {
            // 从右向左找小于 x 的数
            while (i < j && s[j] >= x)
            {
                // 左移,直到遇到小于等于 x 的数
                j--;
            }
            if (i < j)
            {
                // 将右侧找到的小于 x 的元素放入左侧坑中,右侧出现一个坑
                // 左侧元素索引后移
                s[i++] = s[j];
            }
            // 从左向右找大于等于 x 的数
            while (i < j && s[i] < x)
            {
                // 右移,直到遇到大于 x 的数
                i++;
            }
            if (i < j)
            {
                // 将左侧找到的元素放入右侧坑中,左侧出现一个坑
                // 右侧元素索引向前移动
                s[j--] = s[i];
            }
        }
        // 此时 i=j, 将保存在 x 中的数填入坑中
        s[i] = x;
        quickSort(s, l, i - 1); // 递归调用
        quickSort(s, i + 1, r);
    }
}

# 线程调用

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mythread.h"
#include <QThread>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 当运行,用户点击按钮,就要调用子线程生成随机数,传递给主线程
    //1, 创建子线程对象,
//    QThread* t1 = new QThread (this);  // 添加之后会析构申请的空间
//    QThread* t2 = new QThread(this);
//    QThread* t3 = new QThread(this);
    QThread* t1 = new QThread;
    QThread* t2 = new QThread;
    QThread* t3 = new QThread;
    //2, 创建任务类的对象
    Generate* gen = new Generate;
    BubbleSort * bubble = new BubbleSort;
    QuickSort * quick = new QuickSort;
    //3, 将任务对象移动到某个子线程中
    gen->moveToThread(t1); // 生成随机数
    bubble->moveToThread(t2);
    quick->moveToThread(t3);
    // 信号和槽,主函数将 starting 的数,传递给子线程的 recNum 用户接受数量
    connect(this,&MainWindow::starting,gen,&Generate::working);
    // 启动子线程,使用信号与槽,当用户点击
    connect(ui->start,&QPushButton::clicked,this,[=]()
    {
        emit starting(10000);
        // 给子线程发送信号
        t1->start(); // 调用子线程运行方法,还没有执行
    });
    // 当有了随机数之后,开始起痘冒泡和快速排序线程
    // 在排序之前,线程要先拿到所需要的数据
    connect(gen,&Generate::sendArray,bubble,&BubbleSort::working);
    connect(gen,&Generate::sendArray,quick,&QuickSort::working);
    // 添加 connect 用于接受子线程传过来的 list 容器随机数
    // 连接子线程,但子线程信号 sendArray 运行时,主线程接受
    connect(gen,&Generate::sendArray,this,[=](QVector <int> list)
    {
        //
        // 主线程开始接受来自子线程发送过来的 list,于此同时子线程开始运行
        t2->start();
        t3->start();
        for(int i =0;i<list.size();i++)
        {
            ui->randlist->addItem(QString::number(list.at(i)));
        }
    });
    // 排序运行之后,将排序好的数据放到主线程
    connect(bubble,&BubbleSort::finish,this,[=](QVector<int> list)
    {
        for(int i =0;i<list.size();++i)
        {
            ui->bubblelist->addItem(QString::number(list.at(i)));
        }
    });
    connect(quick,&QuickSort::finish,this,[=](QVector<int> list)
    {
        for(int i =0;i<list.size();++i)
        {
            ui->quicklist->addItem(QString::number(list.at(i)));
        }
    });
    // 手写销毁资源
    connect(this,&MainWindow::destroy,this,[=]()
    {
        t1->quit();
        t1->wait();
        t1->deleteLater(); // 释放空间
        t2->quit();
        t2->wait();
        t2->deleteLater(); // 释放空间
        t3->quit();
        t3->wait();
        t3->deleteLater(); // 释放空间
        gen->deleteLater();
        bubble->deleteLater();
        quick->deleteLater();
    });
}
MainWindow::~MainWindow()
{
    delete ui;
}

# 3, 线程池

创建子线程

  • 引用头文件
#include <QRunnable>
#include <QVector>
#include <QObject>

# 头文件

// 创建的子线程,生成随机数
class Generate : public QObject, public QRunnable
{
    Q_OBJECT
public:
    explicit Generate(QObject *parent = nullptr);
    // 接受主线程传过来的参数,随机数 num
    void recNum(int num);
    // 子线程运行函数
    void run() override;
signals:
    // 使用信号槽将数据传递给主线程,界面操作只能由主线程来进行
    void sendArray(QVector<int> num);
public slots:
private:
    // 设置信号槽接受主线程传过来的数据
    int m_num;
};
// 冒泡排序
class BubbleSort : public QObject, public QRunnable
{
    Q_OBJECT
public:
    explicit BubbleSort(QObject *parent = nullptr);
    // 接受主线程传过来的参数,数组
    void recArray(QVector<int> list);
    // 子线程运行函数
    void run() override;
signals:
    // 使用信号槽将数据传递给主线程,界面操作只能由主线程来进行
    // 发送的有序数组
    void finish(QVector<int> list);
public slots:
private:
    // 设置信号槽接受主线程传过来的数据
    QVector<int> m_list;
};
// 快速排序
class QuickSort : public QObject, public QRunnable
{
    Q_OBJECT
public:
    explicit QuickSort(QObject *parent = nullptr);
    // 接受主线程传过来的参数,随机数 num
    void recArray(QVector<int> list);
    // 子线程运行函数
    void run() override;
signals:
    // 使用信号槽将数据传递给主线程,界面操作只能由主线程来进行
    void finish(QVector<int> list);
private:
    // 设置信号槽接受主线程传过来的数据
    QVector<int> m_list;
    // 实现快速排序算法
    // 容器,起始位置,结束位置
    void quickSort(QVector<int> &list,int l,int r);
};

# 函数实现

#include "mythread.h"
#include <QElapsedTimer>  // 记录时间
#include <QtDebug>
#include <QThread>
Generate::Generate(QObject *parent) : QObject(parent),QRunnable()
{
    setAutoDelete(true);
}
void Generate::recNum(int num)
{
    m_num = num;
}
void Generate::run()
{
    qDebug()<< "生成随机数的线程地址" <<QThread::currentThread();
    // 存放随机数 vector 容器
    QVector<int> list;  // 子线程生成数据,要通过传递给主线程
    QElapsedTimer time;
    time.start();// 开始记录
    for (int i = 0;i < m_num;++i)
    {
        // 从尾部插入
        list.push_back(qrand()%100000);
    }
    qint64 milsec = time.elapsed(); // 毫秒
    qDebug()<< "生成" <<m_num << "个随机总数用时"<<milsec<<"毫秒";
    // 发送给主线程
    emit sendArray(list); // 将数据发给主线程
}
// 冒泡排序,补齐 parent
BubbleSort::BubbleSort(QObject *parent) : QObject(parent),QRunnable()
{
    setAutoDelete(true);
}
// 接受传递的 vector 变量
void BubbleSort::recArray(QVector<int> list)
{
    m_list = list;
}
// 实现冒泡排序,实现相邻两个元素的交换
void BubbleSort::run()
{
    qDebug()<< "冒泡排序的线程地址" <<QThread::currentThread();
    // 存放随机数 vector 容器
    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;
            }
        }
    }
    qint64 milsec = time.elapsed();
    qDebug()<< "冒泡排序用时" <<milsec<<"毫秒";
    // 发送给主线程
    emit finish(m_list); // 将数据发给主线程
}
// 快速,补齐 parent
QuickSort::QuickSort(QObject *parent) : QObject(parent),QRunnable()
{
    setAutoDelete(true); // 自动释放空间
}
// 接受传递的 vector 变量
void QuickSort::recArray(QVector<int> list)
{
    m_list = list;
}
// 实现快速排序
void QuickSort::run()
{
    qDebug()<< "快速排序的线程地址" <<QThread::currentThread();
    // 存放随机数 vector 容器
    QElapsedTimer time;
    time.start();
    // 快速排序算法
    quickSort(m_list,0,m_list.size()-1);
    qint64 milsec = time.elapsed();
    qDebug()<< "快速排序用时" <<milsec<<"毫秒";
    // 发送给主线程
    emit finish(m_list); // 将数据发给主线程
}
// 快排算法
void QuickSort::quickSort(QVector<int> &s, int l, int r)
{
    if(l < r)
    {
        int i = l,j=r;
        // 拿出第一个元素,保存到 x 中,第一个位置为空
        int x = s[l];
        while (i < j)
        {
            // 从右向左找小于 x 的数
            while (i < j && s[j] >= x)
            {
                // 左移,直到遇到小于等于 x 的数
                j--;
            }
            if (i < j)
            {
                // 将右侧找到的小于 x 的元素放入左侧坑中,右侧出现一个坑
                // 左侧元素索引后移
                s[i++] = s[j];
            }
            // 从左向右找大于等于 x 的数
            while (i < j && s[i] < x)
            {
                // 右移,直到遇到大于 x 的数
                i++;
            }
            if (i < j)
            {
                // 将左侧找到的元素放入右侧坑中,左侧出现一个坑
                // 右侧元素索引向前移动
                s[j--] = s[i];
            }
        }
        // 此时 i=j, 将保存在 x 中的数填入坑中
        s[i] = x;
        quickSort(s, l, i - 1); // 递归调用
        quickSort(s, i + 1, r);
    }
}

# 主函数调用

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mythread.h"
#include <QThreadPool>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 当运行,用户点击按钮,就要调用子线程生成随机数,传递给主线程
    // 创建任务类对象
    Generate* gen = new Generate;
    BubbleSort * bubble = new BubbleSort;
    QuickSort * quick = new QuickSort;
    // 信号和槽,主函数将 starting 的数,传递给子线程的 recNum 用户接受数量
    connect(this,&MainWindow::starting,gen,&Generate::recNum);
    // 启动子线程,使用信号与槽,当用户点击
    connect(ui->start,&QPushButton::clicked,this,[=]()
    {
        emit starting(10000);
        // 给子线程发送信号
        QThreadPool::globalInstance()->start(gen); // 线程池中运行
    });
    // 当有了随机数之后,开始起痘冒泡和快速排序线程
    // 在排序之前,线程要先拿到所需要的数据
    connect(gen,&Generate::sendArray,bubble,&BubbleSort::recArray);
    connect(gen,&Generate::sendArray,quick,&QuickSort::recArray);
    // 添加 connect 用于接受子线程传过来的 list 容器随机数
    // 连接子线程,但子线程信号 sendArray 运行时,主线程接受
    connect(gen,&Generate::sendArray,this,[=](QVector <int> list)
    {
        //
        // 主线程开始接受来自子线程发送过来的 list,于此同时子线程开始运行
        QThreadPool::globalInstance()->start(bubble); // 线程池中运行
        QThreadPool::globalInstance()->start(quick); // 线程池中运行
        for(int i =0;i<list.size();i++)
        {
            ui->randlist->addItem(QString::number(list.at(i)));
        }
    });
    // 排序运行之后,将排序好的数据放到主线程
    connect(bubble,&BubbleSort::finish,this,[=](QVector<int> list)
    {
        for(int i =0;i<list.size();++i)
        {
            ui->bubblelist->addItem(QString::number(list.at(i)));
        }
    });
    connect(quick,&QuickSort::finish,this,[=](QVector<int> list)
    {
        for(int i =0;i<list.size();++i)
        {
            ui->quicklist->addItem(QString::number(list.at(i)));
        }
    });
}
MainWindow::~MainWindow()
{
    delete ui;
}

# 4,线程

# 头文件

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QVector>
// 创建的子线程,生成随机数
class Generate : public QThread
{
    Q_OBJECT
public:
    explicit Generate(QObject *parent = nullptr);
    // 接受主线程传过来的参数,随机数 num
    void recNum(int num);
protected:
    // 子线程运行函数
    void run() override;
signals:
    // 使用信号槽将数据传递给主线程,界面操作只能由主线程来进行
    void sendArray(QVector<int> num);
public slots:
private:
    // 设置信号槽接受主线程传过来的数据
    int m_num;
};
// 冒泡排序
class BubbleSort : public QThread
{
    Q_OBJECT
public:
    explicit BubbleSort(QObject *parent = nullptr);
    // 接受主线程传过来的参数,数组
    void recArray(QVector<int> list);
protected:
    // 子线程运行函数
    void run() override;
signals:
    // 使用信号槽将数据传递给主线程,界面操作只能由主线程来进行
    // 发送的有序数组
    void finish(QVector<int> list);
public slots:
private:
    // 设置信号槽接受主线程传过来的数据
    QVector<int> m_list;
};
// 快速排序
class QuickSort : public QThread
{
    Q_OBJECT
public:
    explicit QuickSort(QObject *parent = nullptr);
    // 接受主线程传过来的参数,随机数 num
    void recArray(QVector<int> list);
protected:
    // 子线程运行函数
    void run() override;
signals:
    // 使用信号槽将数据传递给主线程,界面操作只能由主线程来进行
    void finish(QVector<int> list);
public slots:
private:
    // 设置信号槽接受主线程传过来的数据
    QVector<int> m_list;
    // 实现快速排序算法
    // 容器,起始位置,结束位置
    void quickSort(QVector<int> &list,int l,int r);
};
#endif // MYTHREAD_H

# 函数实现

#include "mythread.h"
#include <QElapsedTimer>  // 记录时间
#include <QtDebug>
Generate::Generate(QObject *parent) : QThread(parent)
{
}
void Generate::recNum(int num)
{
    m_num = num;
}
void Generate::run()
{
    qDebug()<< "生成随机数的线程地址" <<QThread::currentThread();
    // 存放随机数 vector 容器
    QVector<int> list;  // 子线程生成数据,要通过传递给主线程
    QElapsedTimer time;
    time.start();// 开始记录
    for (int i = 0;i < m_num;++i)
    {
        // 从尾部插入
        list.push_back(qrand()%100000);
    }
    qint64 milsec = time.elapsed(); // 毫秒
    qDebug()<< "生成" <<m_num << "个随机总数用时"<<milsec<<"毫秒";
    // 发送给主线程
    emit sendArray(list); // 将数据发给主线程
}
// 冒泡排序,补齐 parent
BubbleSort::BubbleSort(QObject *parent) : QThread(parent)
{
}
// 接受传递的 vector 变量
void BubbleSort::recArray(QVector<int> list)
{
    m_list = list;
}
// 实现冒泡排序,实现相邻两个元素的交换
void BubbleSort::run()
{
    qDebug()<< "冒泡排序的线程地址" <<QThread::currentThread();
    // 存放随机数 vector 容器
    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;
            }
        }
    }
    qint64 milsec = time.elapsed();
    qDebug()<< "冒泡排序用时" <<milsec<<"毫秒";
    // 发送给主线程
    emit finish(m_list); // 将数据发给主线程
}
// 快速,补齐 parent
QuickSort::QuickSort(QObject *parent) : QThread(parent)
{
}
// 接受传递的 vector 变量
void QuickSort::recArray(QVector<int> list)
{
    m_list = list;
}
// 实现快速排序
void QuickSort::run()
{
    qDebug()<< "快速排序的线程地址" <<QThread::currentThread();
    // 存放随机数 vector 容器
    QElapsedTimer time;
    time.start();
    // 快速排序算法
    quickSort(m_list,0,m_list.size()-1);
    qint64 milsec = time.elapsed();
    qDebug()<< "快速排序用时" <<milsec<<"毫秒";
    // 发送给主线程
    emit finish(m_list); // 将数据发给主线程
}
// 快排算法
void QuickSort::quickSort(QVector<int> &s, int l, int r)
{
    if(l < r)
    {
        int i = l,j=r;
        // 拿出第一个元素,保存到 x 中,第一个位置为空
        int x = s[l];
        while (i < j)
        {
            // 从右向左找小于 x 的数
            while (i < j && s[j] >= x)
            {
                // 左移,直到遇到小于等于 x 的数
                j--;
            }
            if (i < j)
            {
                // 将右侧找到的小于 x 的元素放入左侧坑中,右侧出现一个坑
                // 左侧元素索引后移
                s[i++] = s[j];
            }
            // 从左向右找大于等于 x 的数
            while (i < j && s[i] < x)
            {
                // 右移,直到遇到大于 x 的数
                i++;
            }
            if (i < j)
            {
                // 将左侧找到的元素放入右侧坑中,左侧出现一个坑
                // 右侧元素索引向前移动
                s[j--] = s[i];
            }
        }
        // 此时 i=j, 将保存在 x 中的数填入坑中
        s[i] = x;
        quickSort(s, l, i - 1); // 递归调用
        quickSort(s, i + 1, r);
    }
}

# 函数调用

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mythread.h"
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 当运行,用户点击按钮,就要调用子线程生成随机数,传递给主线程
    // 创建子线程对象,
    Generate* gen = new Generate;
    BubbleSort * bubble = new BubbleSort;
    QuickSort * quick = new QuickSort;
    // 信号和槽,主函数将 starting 的数,传递给子线程的 recNum 用户接受数量
    connect(this,&MainWindow::starting,gen,&Generate::recNum);
    // 启动子线程,使用信号与槽,当用户点击
    connect(ui->start,&QPushButton::clicked,this,[=]()
    {
        emit starting(10000);
        // 给子线程发送信号
        gen->start(); // 调用子线程运行方法
    });
    // 当有了随机数之后,开始起痘冒泡和快速排序线程
    // 在排序之前,线程要先拿到所需要的数据
    connect(gen,&Generate::sendArray,bubble,&BubbleSort::recArray);
    connect(gen,&Generate::sendArray,quick,&QuickSort::recArray);
    // 添加 connect 用于接受子线程传过来的 list 容器随机数
    // 连接子线程,但子线程信号 sendArray 运行时,主线程接受
    connect(gen,&Generate::sendArray,this,[=](QVector <int> list)
    {
        //
        // 主线程开始接受来自子线程发送过来的 list,于此同时子线程开始运行
        bubble->start();
        quick->start();
        for(int i =0;i<list.size();i++)
        {
            ui->randlist->addItem(QString::number(list.at(i)));
        }
    });
    // 排序运行之后,将排序好的数据放到主线程
    connect(bubble,&BubbleSort::finish,this,[=](QVector<int> list)
    {
        for(int i =0;i<list.size();++i)
        {
            ui->bubblelist->addItem(QString::number(list.at(i)));
        }
    });
    connect(quick,&QuickSort::finish,this,[=](QVector<int> list)
    {
        for(int i =0;i<list.size();++i)
        {
            ui->quicklist->addItem(QString::number(list.at(i)));
        }
    });
    connect(this,&MainWindow::destroyed,this,[=]()
    {
        gen->quit();
        gen->wait();
        gen->deleteLater(); // 释放空间
        bubble->quit();
        bubble->wait();
        bubble->deleteLater(); // 释放空间
        quick->quit();
        quick->wait();
        quick->deleteLater(); // 释放空间
    });
}
MainWindow::~MainWindow()
{
    delete ui;
}