目录
介绍
线程类 QThread
方式1
方式2
案例
线程资源释放
qt为多线程提供了完美的支持,实现多线程一般是从从QTHread中继承定义自己的线程类,QT也提供了QMutexLocker,QwaitCondition等类实现线程同步,与Linux系统或C++中的线程库类似。这里简单介绍下多线程的创建。
常用API:
[virtual protected] void QThread::run();
run()是一个虚函数,如果想让创建的子线程执行某个任务,需要写一个子类让其继承QThread,并且在子类中重写父类的run()方法,函数体就是对应的任务处理流程,当前线程对象调用槽函数start()启动子线程,当子线程被启动,这个run()函数也就在线程内部被调用了。
信号与槽函数:
// 线程中执行的任务完成了, 发出该信号
[signal] void QThread::finished();
// 开始工作之前发出这个信号, 一般不使用
[signal] void QThread::started();[slot] void QThread::quit();
// 启动子线程
[slot] void QThread::start(Priority priority = InheritPriority);
// 线程退出, 可能是会马上终止线程, 一般情况下不使用这个函数
[slot] void QThread::terminate();
创建一个线程类的子类,让其继承QT中的线程类 QThread,重写父类的 run() 方法,启动子线程, 调用 start() 方法。
举例:
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include
#include
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
protected:
void run();
signals:
void curNumber(int num);
};
#endif // MYTHREAD_H
#include "mythread.h"
#include
MyThread::MyThread(QObject *parent)
{
}
void MyThread::run()
{
qDebug() << "当前线程对象的地址: " << QThread::currentThread();
int num = 0;
while(1)
{
emit curNumber(num++);//子线程每秒发出一次信号
if(num == 10000000)
{
break;
}
QThread::usleep(1);
}
qDebug() << "run() 执行完毕, 子线程退出...";
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() << "主线程对象地址: " << QThread::currentThread();
MyThread* m=new MyThread;
connect(m, &MyThread::curNumber, this, [=](int num)//子线程每秒发出一次信号
{
ui->label->setNum(num);
});
connect(ui->pushButton, &QPushButton::clicked, this, [=]()
{
// 启动子线程
m ->start();
});
}
MainWindow::~MainWindow()
{
delete ui;
}
例如:
#ifndef WORK_H
#define WORK_H
#include
class Work : public QObject
{
Q_OBJECT
public:
explicit Work(QObject *parent = nullptr);
void Working();
signals:
void curNumber(int num);
};
#endif // WORK_H
#include "work.h"
#include
#include
Work::Work(QObject *parent)
: QObject{parent}
{
}
void Work::Working()
{
qDebug() << "当前线程对象的地址: " << QThread::currentThread();
int num = 0;
while(1)
{
emit curNumber(num++);//子线程每秒发出一次信号
if(num == 10000000)
{
break;
}
QThread::usleep(1);
}
qDebug() << "run() 执行完毕, 子线程退出...";
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() << "主线程对象地址: " << QThread::currentThread();
QThread* sub = new QThread;//创建线程对象
Work* w=new Work; //创建工作对象,该对象包含业务处理方法,不要指定给创建的对象指定父对象
w->moveToThread(sub); //将工作对象移动到子线程中
sub->start();
connect(ui->startBtn, &QPushButton::clicked, w,&Work::Working);
// 显示数据
connect(w, &Work::curNumber, this, [=](int num)
{
ui->label->setNum(num);
});
}
在一个子线程程中随机生成1000个数,将这些数据交给另一个子线程去排序,后面将排序的结果返回给主线程,主线程再将数据输出到窗口中。
这里采用方案1进行演示:
生成随机数线程:
class Genera : public QThread //该类来生成随机数
{
Q_OBJECT
public:
explicit Genera(QObject *parent = nullptr);
void getnum(int k);
protected:
void run();//重写run方法,生成随机数
private:
int num_; //获取主线程传来的数据,这里为生成随机数的个数
signals:
void sendnum(QVector v);//当随机数生成完后,发射该信号,将数据传给主线程和排序线程
};
Genera::Genera(QObject *parent)
: QThread{parent}
{
}
void Genera::getnum(int k)
{
num_=k;
}
void Genera::run()
{
qDebug()<<"当前线程是"<<" "< v;
QElapsedTimer q;
q.start();
for(int i=0;i
排序线程:
class BubbleSort : public QThread //该类来生成随机数
{
Q_OBJECT
public:
explicit BubbleSort(QObject *parent = nullptr);
void getnum(QVector);//获取生成随机数线程传来的数据
protected:
void run();//进行排序
private:
QVector v;
signals:
void Finish(QVector v);//排序完成后发射该信号,将排序结果给主线程
};
BubbleSort::BubbleSort(QObject *parent)
: QThread{parent}
{
}
void BubbleSort::getnum(QVector list)
{
v=list;
}
void BubbleSort::run()
{
qDebug()<<"当前线程是"<<" "<v[j+1])
{
int tmp=v[j+1];
v[j+1]=v[j];
v[j]=tmp;
}
}
}
int m=q.elapsed();
qDebug()<<"排序的时间是"<<" "<
主线程:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void starting(int num);//生成随机数的个数
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//创建子线程
Genera * g=new Genera;//生成随机数
BubbleSort* b=new BubbleSort;//排序
connect(this,&MainWindow::starting,g,&Genera::getnum);
//启动子线程
connect(ui->pushButton,&QPushButton::clicked,this,[=](){
emit starting(1000);//发射该信号,将生成随机数的个数传给子线程
g->start();
});
connect(g,&Genera::sendnum,b,&BubbleSort::getnum);//排序线程接受生成随机数线程传来的数据
//接受子线程传来的排序数
connect(g,&Genera::sendnum,this,[=](QVector v){
//说明随机生成数已生成好
b->start();
for(int i=0;ilistWidget->addItem(QString::number(v.at(i)));
}
});
connect(b,&BubbleSort::Finish,this,[=](QVector v){
for(int i=0;ilistWidget_2->addItem(QString::number(v.at(i)));
}
});
}
MainWindow::~MainWindow()
{
delete ui;
}
结果:
1.创建线程时,给它指明父对象,让其添加到对象树列表中。
2.手动释放,调用quit,wait,delete:例如,在上面的代码中,new出来的时局部变量:
connect(this,&MainWindow::destroyed,this,[=](){
g->quit();
g->wait();
g->deleteLater();//类似与c++中delete
});