QT多线程的示例

想象现在有一个场景,一共有三个线程线程A需要产生1000以内的随机数,线程B需要对这些随机数进行冒泡排序,线程C需要对这些随机数进行快速排序,主线程用来显示线程A的随机数,并且显示线程A和线程B的处理结果,这里我们还可以对比一下快速排序和冒泡排序的速度。
我们设计UI界面如下:
在这里插入图片描述
这个UI界面用到了QListWidget、QPushbutton、QGroupBox控件。
然后我们写三个线程类,把三个线程类都放在MyThread这个文件中,代码如下:

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QVector>
#include <QRandomGenerator>
#pragma execution_character_set("utf-8")

class Generate : public QThread
{
    Q_OBJECT
public:
    explicit Generate(QObject *parent = nullptr);

signals:
    void SendArray(QVector<int> num);
public slots:
    void RecviveNum(int num);
protected:
    void run() override;
private:
    int m_num;
};

class MBupple : public QThread
{
    Q_OBJECT
public:
    explicit MBupple(QObject *parent = nullptr);

signals:
    void FinishBupple(QVector<int> flist);
public slots:
    void RecviveNum(QVector<int> rlist);
protected:
    void run() override;
private:
    QVector<int> m_list;
};

class MQuick : public QThread
{
    Q_OBJECT
public:
    explicit MQuick(QObject *parent = nullptr);
signals:
    void FinishQuick(QVector<int> flist);
public slots:
    void RecviveNum(QVector<int> rlist);
protected:
    void run() override;
private:
    QVector<int> m_list;
private:
    void quickSort(QVector<int> &list,int l,int r);
};
#endif // MYTHREAD_H

Generate类用来生成随机数,它有一个槽函数void RecviveNum(int num);这个是用来接收来自主线程发来的随机数的数量,还有一个 void SendArray(QVector num);信号,这个是把生成好的随机数,分别发给主线程显示,和其他两个排序线程排序,void run() override;这个重写基类run函数为了生成随机数,不过这里的随机数并不是真正意义上的随机数,而是伪随机数。
以下是Generate的函数:

Generate::Generate(QObject *parent) : QThread(parent){
}
void Generate::RecviveNum(int num){
    m_num=num;
}
void Generate::run(){
    qDebug()<<"生成随机数的线程ID号为"<<QThread::currentThread();
    QElapsedTimer m_timer;
    m_timer.start();
    QVector<int> randList;
    for(int i=0;i<m_num;i++){
        randList.push_back(qrand()%100000);
    }
    int m_delaytime = m_timer.elapsed();
    qDebug()<<"生成"<<m_num<<"个随机数总共用时:"<<m_delaytime<<"毫秒";
    emit SendArray(randList);
}

MBupple类主要来进行把来自Generate的随机数进行冒泡排序,它的run函数就是冒泡排序,它的FinishBupple函数主要是将排序好的随机数发送给主线程显示,它的RecviveNum函数是拿到来自Generate生成的随机数,以下为实现代码:

MBupple::MBupple(QObject *parent) : QThread(parent{
}
void MBupple::RecviveNum(QVector<int> rlist)
{
    m_list=rlist;
}

void MBupple::run()
{
    qDebug()<<"冒泡排序的线程ID号为"<<QThread::currentThread();
    QElapsedTimer m_timer;
    m_timer.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 m_delaytime = m_timer.elapsed();
    qDebug()<<"冒泡排序随机数总共用时:"<<m_delaytime<<"毫秒";
    emit FinishBupple(m_list);
}

MQuick类和MBupple一样,我这里只给出代码:

MQuick::MQuick(QObject *parent) : QThread(parent)
{

}

void MQuick::RecviveNum(QVector<int> rlist)
{
    m_list=rlist;
}

void MQuick::run()
{
    qDebug()<<"快速排序的线程ID号为"<<QThread::currentThread();
    QElapsedTimer m_timer;
    m_timer.start();
    int temp;
    quickSort(m_list,0,m_list.size()-1);
    int m_delaytime = m_timer.elapsed();
    qDebug()<<"快速排序随机数总共用时:"<<m_delaytime<<"毫秒";
    emit FinishQuick(m_list);
}

void MQuick::quickSort(QVector<int> &s,int l,int r){
    if(l<r){
        int i=l,j=r;
        int x=s[l];
        while(i<j){
            while(i<j&&s[j]>=x){
                j--;
            }
            if(i<j){
                s[i++]=s[j];
            }

            while(i<j&&s[i]<x){
                i++;
            }
            if(i<j){
                s[j--]=s[i];
            }
        }
        s[i]=x;
        quickSort(s,l,i-1);
        quickSort(s,i+1,r);
    }
}

然后是主线程,主线程主要负责显示生成的随机数以及排序的结果
在这里插入图片描述
这里给出代码:
cpp:

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    gen=new Generate;
    mbu=new MBupple;
    mqu=new MQuick;
    connect(this,&Widget::SendNum,gen,&Generate::RecviveNum);
    connect(gen,&Generate::SendArray,this,&Widget::ReceiveArray);
    connect(gen,&Generate::SendArray,mbu,&MBupple::RecviveNum);
    connect(gen,&Generate::SendArray,mqu,&MQuick::RecviveNum);
    connect(mbu,&MBupple::FinishBupple,this,&Widget::ReceiveBuppleArray);
    connect(mqu,&MQuick::FinishQuick,this,&Widget::ReceiveQuickArray);
}

Widget::~Widget()
{
    delete ui;
    if(gen!=nullptr){
        delete gen;
        gen=nullptr;
    }
    if(mbu!=nullptr){
        delete mbu;
        mbu=nullptr;
    }

    if(mqu!=nullptr){
        delete mqu;
        mqu=nullptr;
    }
  
}

void Widget::ReceiveArray(QVector<int> randlist)
{
    m_receivelist=randlist;
    for(int i=0;i<m_receivelist.size();i++){
        ui->Randomlist->addItem(QString::number(m_receivelist.at(i)));
    }
    //启动排序线程
    mbu->start();
    mqu->start();
}

void Widget::ReceiveBuppleArray(QVector<int> randlist)
{
    m_receivelist=randlist;
    for(int i=0;i<m_receivelist.size();i++){
        ui->Bubblelist->addItem(QString::number(m_receivelist.at(i)));
    }
}

void Widget::ReceiveQuickArray(QVector<int> randlist)
{
    m_receivelist=randlist;
    for(int i=0;i<m_receivelist.size();i++){
        ui->Quicklist->addItem(QString::number(m_receivelist.at(i)));
    }
}

void Widget::on_btnstart_clicked()
{
    emit SendNum(10000);
    gen->start();
}

.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QVector>
#include "mythread.h"
#pragma execution_character_set("utf-8")
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
signals:
    //向子线程发送生成随机数个数
    void SendNum(int num);
    //发送随机数给冒泡 快速线程
    void SendList(QVector<int> list);
private:
    Ui::Widget *ui;
    QVector<int> m_receivelist;
    Generate* gen=nullptr;
    MBupple* mbu=nullptr;
    MQuick* mqu=nullptr;
public slots:
    //接收子线程随机数
    void ReceiveArray(QVector<int> randlist);

    void ReceiveBuppleArray(QVector<int> randlist);
    void ReceiveQuickArray(QVector<int> randlist);

private slots:
    void on_btnstart_clicked();
};
#endif // WIDGET_H

记得在main.cpp里注册类型,不然传递数据有问题,主要是为了支持信号与槽的机制,方便元对象处理跨线程的数据以及跨dll的数据,保证数据的可靠安全,准确判断数据的类型。

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    qRegisterMetaType<QVector<int>>("QVector<int>");
    Widget w;
    w.show();
    return a.exec();
}

这下可以看到三个线程有不同的id号地址,也可以比较出排序的速度
在这里插入图片描述
可能中间这种不停地用信号与槽机制传递数据比较混乱一点,但是仔细捋捋还是能搞懂,另外可以考虑单例模式来实现这种繁琐的数据传递应该更好一点。
另一种线程实现方式:
mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QVector>
#include <QRandomGenerator>
#include <QThread>
#pragma execution_character_set("utf-8")

class Generate : public QObject
{
    Q_OBJECT
public:
    explicit Generate(QObject *parent = nullptr);

signals:
    void SendArray(QVector<int> num);
public:
    void working(int num);
};

class MBupple : public QObject
{
    Q_OBJECT
public:
    explicit MBupple(QObject *parent = nullptr);

signals:
    void FinishBupple(QVector<int> flist);
public:
    void working(QVector<int> m_list);
};

class MQuick : public QObject
{
    Q_OBJECT
public:
    explicit MQuick(QObject *parent = nullptr);
signals:
    void FinishQuick(QVector<int> flist);
public:
    void working(QVector<int> m_list);
private:
    void quickSort(QVector<int> &list,int l,int r);
};
#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include <QElapsedTimer>
#include <QDebug>
Generate::Generate(QObject *parent) : QObject(parent)
{

}

void Generate::working(int num){
    qDebug()<<"生成随机数的线程ID号为"<<QThread::currentThread();
    QElapsedTimer m_timer;
    m_timer.start();
    QVector<int> randList;
    for(int i=0;i<num;i++){
        randList.push_back(qrand()%100000);
    }
    int m_delaytime = m_timer.elapsed();
    qDebug()<<"生成"<<num<<"个随机数总共用时:"<<m_delaytime<<"毫秒";
    emit SendArray(randList);
}

MBupple::MBupple(QObject *parent) : QObject(parent)
{

}

void MBupple::working(QVector<int> m_list)
{
    qDebug()<<"冒泡排序的线程ID号为"<<QThread::currentThread();
    QElapsedTimer m_timer;
    m_timer.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 m_delaytime = m_timer.elapsed();
    qDebug()<<"冒泡排序随机数总共用时:"<<m_delaytime<<"毫秒";
    emit FinishBupple(m_list);
}


MQuick::MQuick(QObject *parent) : QObject(parent)
{

}

void MQuick::working(QVector<int> m_list)
{
    qDebug()<<"快速排序的线程ID号为"<<QThread::currentThread();
    QElapsedTimer m_timer;
    m_timer.start();
    int temp;
    quickSort(m_list,0,m_list.size()-1);
    int m_delaytime = m_timer.elapsed();
    qDebug()<<"快速排序随机数总共用时:"<<m_delaytime<<"毫秒";
    emit FinishQuick(m_list);
}

void MQuick::quickSort(QVector<int> &s,int l,int r){
    if(l<r){
        int i=l,j=r;
        int x=s[l];
        while(i<j){
            while(i<j&&s[j]>=x){
                j--;
            }
            if(i<j){
                s[i++]=s[j];
            }

            while(i<j&&s[i]<x){
                i++;
            }
            if(i<j){
                s[j--]=s[i];
            }
        }
        s[i]=x;
        quickSort(s,l,i-1);
        quickSort(s,i+1,r);
    }
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QVector>
#include "mythread.h"
#include <QThread>


#pragma execution_character_set("utf-8")
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
signals:
    //向子线程发送生成随机数个数
    void SendNum(int num);
    //发送随机数给冒泡 快速线程
    void SendList(QVector<int> list);
private:
    Ui::Widget *ui;
    QVector<int> m_receivelist;
    Generate* gen=nullptr;
    MBupple* mbu=nullptr;
    MQuick* mqu=nullptr;
public slots:
    //接收子线程随机数
    void ReceiveArray(QVector<int> randlist);
    void ReceiveBuppleArray(QVector<int> randlist);
    void ReceiveQuickArray(QVector<int> randlist);

private slots:
    void on_btnstart_clicked();
private:
    QThread* t1;
    QThread* t2;
    QThread* t3;

};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //线程对象
    t1=new QThread;
    t2=new QThread;
    t3=new QThread;
    //任务对象
    gen=new Generate;
    mbu=new MBupple;
    mqu=new MQuick;
    //任务对象加入线程
    gen->moveToThread(t1);
    mbu->moveToThread(t2);
    mqu->moveToThread(t3);
    connect(this,&Widget::SendNum,gen,&Generate::working);


    connect(gen,&Generate::SendArray,this,&Widget::ReceiveArray);
    connect(gen,&Generate::SendArray,mbu,&MBupple::working);
    connect(gen,&Generate::SendArray,mqu,&MQuick::working);
    connect(mbu,&MBupple::FinishBupple,this,&Widget::ReceiveBuppleArray);
    connect(mqu,&MQuick::FinishQuick,this,&Widget::ReceiveQuickArray);

    connect(this,&Widget::destroy,this,[=]{
        t1->quit();
        t1->wait();
        t1->deleteLater();
        t2->quit();
        t2->wait();
        t2->deleteLater();
        t3->quit();
        t3->wait();
        t3->deleteLater();
        gen->deleteLater();
        mbu->deleteLater();
        mqu->deleteLater();

    });
}

Widget::~Widget()
{
    delete ui;
    if(gen!=nullptr){
        delete gen;
        gen=nullptr;
    }

    if(mbu!=nullptr){
        delete mbu;
        mbu=nullptr;
    }

    if(mqu!=nullptr){
        delete mqu;
        mqu=nullptr;
    }
}

void Widget::ReceiveArray(QVector<int> randlist)
{
    m_receivelist=randlist;
    for(int i=0;i<m_receivelist.size();i++){
        ui->Randomlist->addItem(QString::number(m_receivelist.at(i)));
    }
    //启动排序线程
    t2->start();
    t3->start();
}

void Widget::ReceiveBuppleArray(QVector<int> randlist)
{
    m_receivelist=randlist;
    for(int i=0;i<m_receivelist.size();i++){
        ui->Bubblelist->addItem(QString::number(m_receivelist.at(i)));
    }
}

void Widget::ReceiveQuickArray(QVector<int> randlist)
{
    m_receivelist=randlist;
    for(int i=0;i<m_receivelist.size();i++){
        ui->Quicklist->addItem(QString::number(m_receivelist.at(i)));
    }
}

void Widget::on_btnstart_clicked()
{
    emit SendNum(10000);
    t1->start();
}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值