Qt中如何做到主线程更新ui,子线程进行耗时操作(面试问题)
如果ui更新出现了卡顿,那主要是因为GUI线程函数进行了耗时操作,sleep或者wait
所以一般处理是ui只用来收集参数,发送和接受信号,以及更新ui,而那些耗时操作是放在Worker类中,再通过MovetoThread()移动到子线程,然后主线程通过QueuedConnection调用Worker的槽函数
主线程不能通过wait()去等待子线程,而工作子线程也不能操纵ui
下面有个例子,涉及到线程的开始、停止、销毁,以及子线程中的休眠
Worker类
点击查看代码
#include "worker.h"
Worker::Worker(QObject *parent)
: QObject{parent}
{
}
void Worker::processedData(QVector<int>vv)
{
QVector<int>temp;
temp.resize(vv.size());
for(int i=0;i<temp.size();i++)
{
//查看当前线程是否有中断请求标记
if(QThread::currentThread()->isInterruptionRequested())
{
qDebug()<<"任务取消";
emit tastcancel();
return;
}
if(i%20==0)
{
qDebug()<<i;
emit is_twenty(i);
QThread::msleep(100);
}
}
}
点击查看代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->m_thread=new QThread();
this->m_worker=new Worker();
this->m_worker->moveToThread(this->m_thread);
//开始线程
connect(this,&MainWindow::start_dataPreceed,this->m_worker,&Worker::processedData,Qt::QueuedConnection);
connect(this->m_worker,&Worker::is_twenty,this,&MainWindow::on_istwenty,Qt::QueuedConnection);
//线程停止的操作
connect(this->m_worker,&Worker::tastcancel,this,[this]
{
ui->label_2->setText("线程停止");
});
//线程结束
connect(this->m_thread,&QThread::finished,this->m_worker,&QObject::deleteLater);
// worker销毁后,清空线程指针防止野指针
connect(m_worker, &QObject::destroyed, this, [this](){
m_thread->deleteLater();
m_thread = nullptr;
m_worker = nullptr;
});
this->m_thread->start();
}
MainWindow::~MainWindow()
{
this->m_thread->requestInterruption();
this->m_thread->quit();//退出线程的事件循环,不再接收新的信号(但是会把当前函数执行完)
this->m_thread->wait(1000);//等待线程完成,会阻塞主线程
delete ui;
}
//线程启动
void MainWindow::on_pushButton_clicked()
{
QVector<int>vv;
for(auto i=0;i<10000;i++)
{
vv.push_back(i);
}
emit start_dataPreceed(vv);
}
void MainWindow::on_istwenty(int temp)
{
ui->label->setText(QString::number(temp));
}
//终止线程
void MainWindow::on_pushButton_2_clicked()
{
if(this->m_thread&&this->m_thread->isRunning())
{
this->m_thread->requestInterruption();
}
}
还有一个问题:如果我们用任务队列的话,那ui的刷新频率达不到发送接收信号的更新频率怎么办呢(也就是生产速度大于消费速度)
我们可以用有界队列来解决,比如设定最大边界为5000
如果超过了那就让生产者停止一会,等待消费者消费,或者我们直接把旧数据丢掉
然后我们也可以把数据批量发送给主线程,防止更新一条就发送一条,减少信号与槽的调用
之后我们也可以限制主线程的刷新频率,定时刷新,每100ms刷新一次?
还有就是要减少大数据的拷贝,比如vector容器每个线程都要拷贝一份?不可以,我们最好多线程公用这一个数据,但是加锁
浙公网安备 33010602011771号