QT多线程的三种实现方法(排序算法案例)

写在前面

1、QThread类,使用run方法

2、使用movetothread方法

3、使用线程池

区别

1、使用 moveToThread 方法:

        通过将QObject子对象移动到线程中执行,可以实现对象在不同线程中的管理和执行。适合于将现有的对象移动到其他线程中执行,比较灵活。

2、封装 QThread 类并调用 run 方法:

        创建一个继承自 QThread 的子类,并重写 run 方法来实现线程执行的逻辑。可以更直接地控制线程的创建和执行过程。可以在 run 方法中实现线程的主要逻辑,使得代码更清晰。

3、线程池

         继承 QRunnable 并使用 QThreadPool::globalInstance() 线程池,通过继承 QRunnable 类并在其中实现 run 方法,然后将 QRunnable 对象添加到全局线程池中执行。适用于需要管理多个任务的情况,可以方便地控制任务的执行和线程池的管理。         

        总的来说,使用 moveToThread 方法更适合于将现有的对象移动到其他线程中执行,而封装 QThread 类并调用 run 方法更适合于直接控制线程的创建和执行过程。选择哪种方式取决于具体的需求和设计。

案例----多种排序算法

一、不使用多线程的情况

随机生成10000个自然数,以此进行冒泡、选择、插入和快速排序

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(this->ui->pushButtonGen, &QPushButton::clicked, this, &MainWindow::GenerateArr);
    connect(this->ui->pushButtonSort, &QPushButton::clicked, this, [=](){
        QElapsedTimer timer;
        timer.start();
        BubbleSort(m_arr);
        SelectSort(m_arr);
        InsertSort(m_arr);
        QuickSortFunction(m_arr);
        int TotalTime = timer.elapsed();
        this->ui->label_total->setText("Total Time: "+QString::number(TotalTime)+" ms");
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::GenerateArr()
{
    for (int i = 0; i < 10000; ++i) {
        int randomNumber = rand() % 10000;
        this->m_arr.append(randomNumber);
    }
    QStringList arrlist;
    for (int a : m_arr) {
        arrlist.append(QString::number(a));
    }
    QStringListModel *model = new QStringListModel(arrlist);


    this->ui->listViewOrigin->setModel(model);
}

void MainWindow::BubbleSort(QVector<int> arr)
{

    QElapsedTimer timer;
    timer.start();
    for (int i = 0; i < arr.length(); ++i) {
        for (int j = 0; j < arr.length()-i-1; ++j) {
            if(arr[j]>arr[j+1]){
                std::swap(arr[j],arr[j+1]);
            }
        }
        this->ui->progressBarBubble->setValue((i+1) * 100 / arr.length());
    }
    int time = timer.elapsed();
    QStringList arrlist;
    for (int a : arr) {
        arrlist.append(QString::number(a));
    }
    QStringListModel *model = new QStringListModel(arrlist);
    this->ui->label_bubble->setText("time: "+QString::number(time)+" ms");

    this->ui->listViewBubble->setModel(model);
}

void MainWindow::SelectSort(QVector<int> arr)
{
    QElapsedTimer timer;
    timer.start();
    for (int i = 0; i < arr.length(); ++i) {
        int minIndex = i;
        for (int j = i; j < arr.length(); ++j) {
            if(arr[j]<arr[minIndex]){
                 minIndex = j;
            }
        }
        std::swap(arr[i],arr[minIndex]);
        this->ui->progressBarSelect->setValue((i+1) * 100 / arr.length());
    }
    int time = timer.elapsed();
    QStringList arrlist;
    for (int a : arr) {
        arrlist.append(QString::number(a));
    }
    QStringListModel *model = new QStringListModel(arrlist);
    this->ui->label_select->setText("time: "+QString::number(time)+" ms");

    this->ui->listViewSelect->setModel(model);
}

void MainWindow::InsertSort(QVector<int> arr)
{
    QElapsedTimer timer;
    timer.start();
    for (int i = 1; i < arr.length(); ++i) {
        for (int j = i; j > 0; --j) {
            if(arr[j-1]>arr[j]){
                std::swap(arr[j-1],arr[j]);
            }
            else{
                break;
            }
        }
        this->ui->progressBarInsert->setValue((i+1) * 100 / arr.length());
    }
    int time = timer.elapsed();
    QStringList arrlist;
    for (int a : arr) {
        arrlist.append(QString::number(a));
    }
    QStringListModel *model = new QStringListModel(arrlist);
    this->ui->label_insert->setText("time :"+QString::number(time)+" ms");

    this->ui->listViewInsert->setModel(model);
}

int MainWindow::getMid(QVector<int> &arr, int low, int high)
{
    int mid = arr[high]; // 选择中间位置的元素作为中间值
    int left = low - 1;
    for (int i = low; i < high; ++i) {
        if (arr[i] < mid) {
            left++;
            std::swap(arr[i], arr[left]);
        }
    }
    std::swap(arr[left + 1], arr[high]);
    return left + 1;
}

void MainWindow::QuickSort(QVector<int> &arr,int low, int high)
{
    if(low<high){
        int mid = getMid(arr, low, high);
        QuickSort(arr, low, mid-1);
        QuickSort(arr, mid+1, high);
        // int progress = qRound((mid - low + 1) * 100.0 / (high - low + 1));
        // this->ui->progressBarQuick->setValue(progress);
    }
}

void MainWindow::QuickSortFunction(QVector<int> arr)
{
    QElapsedTimer timer;
    timer.start();
    QuickSort(arr, 0, arr.length()-1);
    int time = timer.elapsed();
    QStringList arrlist;
    for (int a : arr) {
        arrlist.append(QString::number(a));
    }
    QStringListModel *model = new QStringListModel(arrlist);
    this->ui->label_quick->setText("time: "+QString::number(time)+" ms");

    this->ui->listViewQuick->setModel(model);
}

 运行结果:快排遥遥领先,冒泡遥遥落后,总用时4736

二、QThread类方法

思路是对每个排序算法进行线程类封装,在主线程中启动多个子线程(偷懒了,没写快排)

子线程,以冒排为例:

#ifndef SORTTHREAD_H
#define SORTTHREAD_H

#include <QObject>
#include <QThread>
class SortThread : public QThread
{
    Q_OBJECT
public:
    explicit SortThread(QObject *parent = nullptr);
    void run() override;
    void getArr(QVector<int> arr);
signals:
    void finishSort(QVector<int> arr, int time);
    void sendProgressValue(int value);
private:
    QVector<int> m_arr;
};

#endif // SORTTHREAD_H
#include "sortthread.h"

SortThread::SortThread(QObject *parent)
    : QThread{parent}
{}

void SortThread::run()
{
    QElapsedTimer timer;
    timer.start();
    for (int i = 0; i < m_arr.length(); ++i) {
        for (int j = 0; j < m_arr.length()-i-1; ++j) {
            if(m_arr[j]>m_arr[j+1]){
                std::swap(m_arr[j],m_arr[j+1]);
            }
        }
        emit sendProgressValue((i+1)*100/m_arr.length());
    }
    int time = timer.elapsed();
    emit finishSort(m_arr,time);

}

void SortThread::getArr(QVector<int> arr)
{
    this->m_arr = arr;
}

主线程:

#include "insertthread.h"
#include "mainwindow.h"
#include "sortthread.h"
#include "ui_mainwindow.h"

#include <selectSortThread.h>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    SortThread *Sortthread = new SortThread;
    selectSortThread *selectThread = new selectSortThread;
    InsertThread *insertThread = new InsertThread;
    connect(this->ui->pushButtonGen, &QPushButton::clicked, this, &MainWindow::GenerateArr);
    connect(this->ui->pushButtonSort, &QPushButton::clicked, this, [=](){
        Sortthread->getArr(m_arr);
        selectThread->getArr(m_arr);
        insertThread->getArr(m_arr);
        Sortthread->start();
        selectThread->start();
        insertThread->start();
    });

    connect(this->ui->pushButtonSort, &QPushButton::clicked, this, [=](){
        this->beginTiming();
    });
    connect(Sortthread, &SortThread::finishSort, this,[=](QVector<int> arr, int time){
        QStringList arrlist;
        for (int a : arr) {
            arrlist.append(QString::number(a));
        }
        QStringListModel *model = new QStringListModel(arrlist);
        this->ui->listViewBubble->setModel(model);
        this->ui->label_bubble->setText("time: "+QString::number(time)+" ms");
        this->finishedIndex++;
        if(finishedIndex==3){
            this->ui->label_total->setText("time: "+QString::number(m_totalTimer.elapsed())+" ms");
        }
    });
    connect(Sortthread, &SortThread::sendProgressValue, this, [=](int value){
        this->ui->progressBarBubble->setValue(value);
    });
    connect(selectThread, &selectSortThread::finishSort, this, [=](QVector<int> arr, int time){
        QStringList arrlist;
        for (int a : arr) {
            arrlist.append(QString::number(a));
        }
        QStringListModel *model = new QStringListModel(arrlist);
        this->ui->listViewSelect->setModel(model);
        this->ui->label_select->setText("time: "+QString::number(time)+" ms");
        this->finishedIndex++;
        if(finishedIndex==3){
            this->ui->label_total->setText("time: "+QString::number(m_totalTimer.elapsed())+" ms");
        }
    });
    connect(selectThread, &selectSortThread::sendProgressValue, this, [=](int value){
        this->ui->progressBarSelect->setValue(value);
    });
    connect(insertThread, &InsertThread::finishSort, this, [=](QVector<int> arr, int time){
        QStringList arrlist;
        for (int a : arr) {
            arrlist.append(QString::number(a));
        }
        QStringListModel *model = new QStringListModel(arrlist);
        this->ui->listViewInsert->setModel(model);
        this->ui->label_insert->setText("time: "+QString::number(time)+" ms");
        this->finishedIndex++;
        if(finishedIndex==3){
            this->ui->label_total->setText("time: "+QString::number(m_totalTimer.elapsed())+" ms");
        }
    });
    connect(insertThread, &InsertThread::sendProgressValue, this, [=](int value){
        this->ui->progressBarInsert->setValue(value);
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::beginTiming()
{
    this->m_totalTimer.start();
}

结果:总用时节省一半

三、moveToThread()方法

三个任务类:

class BubbleWorker: public QObject
{
    Q_OBJECT
public:
    void sort();
    void getArr(QVector<int> arr);
signals:
    void finishSort(QVector<int> arr);
private:
    QVector<int> m_arr;
};

class SelectWorker: public QObject
{
    Q_OBJECT
public:
    void sort();
    void getArr(QVector<int> arr);
signals:
    void finishSort(QVector<int> arr);
private:
    QVector<int> m_arr;
};

class InsertWorker: public QObject
{
    Q_OBJECT
public:
    void sort();
    void getArr(QVector<int> arr);
signals:
    void finishSort(QVector<int> arr);
private:
    QVector<int> m_arr;
};
void BubbleWorker::sort()
{
    for (int i = 0; i < m_arr.length(); ++i) {
        for (int j = 0; j < m_arr.length()-i-1; ++j) {
            if(m_arr[j]>m_arr[j+1]){
                std::swap(m_arr[j],m_arr[j+1]);
            }
        }
    }
    emit finishSort(m_arr);
}

void BubbleWorker::getArr(QVector<int> arr)
{
    m_arr= arr;
}

void SelectWorker::sort()
{
    for (int i = 0; i < m_arr.length(); ++i) {
        int minIndex = i;
        for (int j = i; j < m_arr.length(); ++j) {
            if(m_arr[j]<m_arr[minIndex]){
                minIndex = j;
            }
        }
        std::swap(m_arr[i],m_arr[minIndex]);
    }

    emit finishSort(m_arr);
}

void SelectWorker::getArr(QVector<int> arr)
{
    m_arr= arr;
}

void InsertWorker::sort()
{
    for (int i = 1; i < m_arr.length(); ++i) {
        for (int j = i; j > 0; --j) {
            if(m_arr[j-1]>m_arr[j]){
                std::swap(m_arr[j-1],m_arr[j]);
            }
            else{
                break;
            }
        }
    }
    emit finishSort(m_arr);
}

void InsertWorker::getArr(QVector<int> arr)
{
    m_arr= arr;
}
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(ui->pushButtonGen, &QPushButton::clicked, this , &MainWindow::GenerateArr);

    BubbleWorker *bworker = new BubbleWorker;
    SelectWorker *sworker = new SelectWorker;
    InsertWorker *iworker = new InsertWorker;
    QThread *t1 = new QThread;
    QThread *t2 = new QThread;
    QThread *t3 = new QThread;
    bworker->moveToThread(t1);
    sworker->moveToThread(t2);
    iworker->moveToThread(t3);
    connect(ui->pushButtonSort, &QPushButton::clicked, this, [=](){
        t1->start();
        t2->start();
        t3->start();
    });
    connect(t1, &QThread::started, this, [=](){
        bworker->getArr(m_arr);
        bworker->sort();
    });
    connect(t2, &QThread::started, this, [=](){
        sworker->getArr(m_arr);
        sworker->sort();
    });
    connect(t3, &QThread::started, this, [=](){
        iworker->getArr(m_arr);
        iworker->sort();
    });
    connect(bworker, &BubbleWorker::finishSort, this, [=](QVector<int> arr){
        QStringList arrlist;
        for (int a : arr) {
            arrlist.append(QString::number(a));
        }
        QStringListModel *model = new QStringListModel(arrlist);
        this->ui->listViewBubble->setModel(model);
    });

    connect(sworker, &SelectWorker::finishSort, this, [=](QVector<int> arr){
        QStringList arrlist;
        for (int a : arr) {
            arrlist.append(QString::number(a));
        }
        QStringListModel *model = new QStringListModel(arrlist);
        this->ui->listViewSelect->setModel(model);
    });

    connect(iworker, &InsertWorker::finishSort, this, [=](QVector<int> arr){
        QStringList arrlist;
        for (int a : arr) {
            arrlist.append(QString::number(a));
        }
        QStringListModel *model = new QStringListModel(arrlist);
        this->ui->listViewInsert->setModel(model);
    });

    connect(this, &MainWindow::destroyed, this, [=](){
        t1->quit();
        t2->quit();
        t3->quit();

        bworker->deleteLater();
        sworker->deleteLater();
        iworker->deleteLater();
    });
}

四、线程池方法

子线程类继承于QRunnable类,重写run方法

class BubbleWorker: public QObject, public QRunnable
{
    Q_OBJECT
public:
    void run() override;
    void getArr(QVector<int> arr);
signals:
    void finishSort(QVector<int> arr);
private:
    QVector<int> m_arr;
};

class SelectWorker: public QObject, public QRunnable
{
    Q_OBJECT
public:
    void run() override;
    void getArr(QVector<int> arr);
signals:
    void finishSort(QVector<int> arr);
private:
    QVector<int> m_arr;
};

class InsertWorker: public QObject, public QRunnable
{
    Q_OBJECT
public:
    void run() override;
    void getArr(QVector<int> arr);
signals:
    void finishSort(QVector<int> arr);
private:
    QVector<int> m_arr;
};


void BubbleWorker::run()
{
    for (int i = 0; i < m_arr.length(); ++i) {
        for (int j = 0; j < m_arr.length()-i-1; ++j) {
            if(m_arr[j]>m_arr[j+1]){
                std::swap(m_arr[j],m_arr[j+1]);
            }
        }
    }
    emit finishSort(m_arr);
}

void BubbleWorker::getArr(QVector<int> arr)
{
    m_arr= arr;
}


void SelectWorker::run()
{
    for (int i = 0; i < m_arr.length(); ++i) {
        int minIndex = i;
        for (int j = i; j < m_arr.length(); ++j) {
            if(m_arr[j]<m_arr[minIndex]){
                minIndex = j;
            }
        }
        std::swap(m_arr[i],m_arr[minIndex]);
    }
    emit finishSort(m_arr);
}

void SelectWorker::getArr(QVector<int> arr)
{
    m_arr= arr;
}



void InsertWorker::run()
{
    for (int i = 1; i < m_arr.length(); ++i) {
        for (int j = i; j > 0; --j) {
            if(m_arr[j-1]>m_arr[j]){
                std::swap(m_arr[j-1],m_arr[j]);
            }
            else{
                break;
            }
        }
    }
    emit finishSort(m_arr);
}

void InsertWorker::getArr(QVector<int> arr)
{
    m_arr= arr;
}


主线程中声明三个子线程,通过globalInstance方法添加到线程池中.

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    BubbleWorker *bworker = new BubbleWorker;
    SelectWorker *sworker = new SelectWorker;
    InsertWorker *iworker = new InsertWorker;
    connect(ui->pushButtonGen, &QPushButton::clicked, this , &MainWindow::GenerateArr);
    connect(ui->pushButtonSort, &QPushButton::clicked, this, [=](){
        bworker->getArr(m_arr);
        sworker->getArr(m_arr);
        iworker->getArr(m_arr);
        QThreadPool::globalInstance()->start(bworker);
        QThreadPool::globalInstance()->start(sworker);
        QThreadPool::globalInstance()->start(iworker);
    });
    connect(bworker, &BubbleWorker::finishSort, this,[=](QVector<int> arr){
        QStringList arrlist;
        for (int a : arr) {
            arrlist.append(QString::number(a));
        }
        QStringListModel *model = new QStringListModel(arrlist);

        this->ui->listViewBubble->setModel(model);
    });
    connect(sworker, &SelectWorker::finishSort, this,[=](QVector<int> arr){
        QStringList arrlist;
        for (int a : arr) {
            arrlist.append(QString::number(a));
        }
        QStringListModel *model = new QStringListModel(arrlist);

        this->ui->listViewSelect->setModel(model);
    });
    connect(iworker, &InsertWorker::finishSort, this,[=](QVector<int> arr){
        QStringList arrlist;
        for (int a : arr) {
            arrlist.append(QString::number(a));
        }
        QStringListModel *model = new QStringListModel(arrlist);

        this->ui->listViewInsert->setModel(model);
    });

    //释放内存
    connect(this, &MainWindow::destroyed, this, [=](){
        bworker->deleteLater();
        sworker->deleteLater();
        iworker->deleteLater();
    });
}

效果:(个人感觉最流畅)

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值