自学内容网 自学内容网

Qt线程常用的3种方式:QThread/QtConcurrent::run/moveTo..

一、前言

        为了避免UI界面卡顿,一般长耗时的任务会通过子线程处理,处理完成后将结果发送给UI线程去显示,Qt提供了多种创建线程的方式,这篇文章介绍常用的3种。

二、QThread

        第一种方式采用继承QThread,然后重写 run()的方法。这种方式存在以下的注意点:

① MyThread假如在UI线程内实例化,那么其槽函数依附的线程在UI线程,导致此槽函数实际在UI线程执行。

run()函数执行完毕后,线程会结束并触发QThread::finished信号,即使重新调用start()启动线程,线程ID也会是新的。

③ 如果在run()函数内,执行QThread::exec,开启事件循环,线程不会finished,除非手动调用quit()方法关闭线程

#include <QObject>
#include <QThread>
#include <QTimer>
class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = nullptr);
    void run() override;
    bool bFlag=false;
    QTimer*timer;
signals:
    void myThreadSend(QString str);
public slots:
    void do_ThreadSlots();
private:

    int count=0;
};

三、QtConcurrent::run

        QtConcurrent提供了一种高级的API,调用线程池内的线程执行长耗时的方法。对于一些临时性的任务,使用这种方式特别方便。由于不是继承自QObject,所以无法使用信号和槽的机制。如果需要在线程执行完成后发出通过UI线程去显示,可以结合QFuture和QFutureWatcher搭配使用。

        注意子线程不要直接刷新UI控件,个别情况下导致报错发生,可以使用QMetaObject::invokeMethod 的方式执行UI线程的方法。

    flag=true;
    QFutureWatcher<int> *watcher=new QFutureWatcher<int>();
    connect(watcher,&QFutureWatcher<int>::finished,this,[watcher,this]()
            {
        int num=watcher->result();
        QMessageBox::information(this,"提示",QString("线程结束,执行到%1").arg(num));
        watcher->deleteLater();
    });
    QFuture<int> future= QtConcurrent::run([=](){
        int ii;
        for (int var = 0; var < 5000; ++var) {
            ii=var;
            //ui->lab_Show->setText(QString::number(var));
            QMetaObject::invokeMethod(this,"on_updatelabel",Qt::ConnectionType::AutoConnection,Q_ARG(int,ii));
            if(flag==false)
            {
                break;
            }
            QThread::msleep(200);
        }
        return ii;
    });
    watcher->setFuture(future);

四、QObject.moveToThread

        相较于继承QThread,这种方式更常用,因为它可以避免QThread子类的槽函数在UI线程内执行的问题。

        一般创建一个继承自QObject的线程类,可以在该类内创建多个槽函数,外部通过信号和槽机制触发时,槽函数会在子线程中执行。

注意:

① 调用start()启动线程后,线程不会主动结束,而是进入等待状态。只有当子类的槽函数被触发时,线程才会被唤醒并执行相应的任务。因此,可以多次触发槽函数,而且线程ID不会改变

② 在子类使用QTimer循环触发信号,执行里面的槽函数,也是在子线程内进行的

class ClassmoveTo:public QObject
{
    Q_OBJECT
public:
    ClassmoveTo();
    ~ClassmoveTo();
    bool flag=false;
    int count;
    QTimer *timer;
public slots:
    void doWork();
    void doWork1();
signals:
    void sendNum(int num);
    void sendStr(QString str);
};


原文地址:https://blog.csdn.net/qq_42537006/article/details/143952506

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!