想象现在有一个场景,一共有三个线程线程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号地址,也可以比较出排序的速度
可能中间这种不停地用信号与槽机制传递数据比较混乱一点,但是仔细捋捋还是能搞懂,另外可以考虑单例模式来实现这种繁琐的数据传递应该更好一点。