首页 > 在QT中加入多线程的方式
头像
橙木
编辑于 2020-12-28 17:25
+ 关注

在QT中加入多线程的方式

近期在解析ts流文件时发现数据量太大,如果在主线程处理会造成界面卡顿,所以需要在QT中加入多线程完成解析数据工作。
通常QT内加入多线程有三种比较方便的方式:
*****分割线------------------------------------
1.moveToThread

新建一个继承QObject a,然后将耗时的工作函数
void dowork()写到这类里面,在主线程new一个Qthread b,再利用

a->moveToThread(b)

移动任务后再启动线程b.start().
通过设置信号与槽的关系触发void dowork()

connect(b, SIGNAL(started()), a, SLOT(dowork()));
connect(b, SIGNAL(finished()), a, SLOT(deleteLater()));

完成触发后需要保证安全退出,第二步已经在得到结束信号后触发析构

disconnect(b, SIGNAL(started()), a, SLOT(doWork()));//断开信号和槽函数联系
disconnect(b, SIGNAL(finished()), a, SLOT(deleteLater()));
 if (b)//退出线程释放内存
 {
     if (b->isRunning())
     {
             b->quit();
              b->wait();
     }
         delete b;
         b = NULL;
 }
 if (a)//释放内存
 {
     delete a;
     a = NULL;
 }

*****分割线------------------------------------
2.QThreadPool
利用QT自带的线程池也很方便,我们需要自己定义一个Task类继承QRunnable

头文件

#ifndef TASK_H
#define TASK_H

#include <QRunnable>

class Task : public QRunnable {

public:
    Task();
    ~Task();
    void run() Q_DECL_OVERRIDE;
};
#endif // TASK_H

实现

#include "task.h"
#include <QDebug>
#include <QThread>
#include <QDateTime>
#include <iostream>
#include <fstream>
#include <QFile>
Task::Task(QString filename) :m_filename(filename) {
}

Task::~Task() {
    qDebug().noquote() << QString("~Task() with ID %1").arg(m_id); // 方便查看对象是否被 delete
}
void Task::run() {
    //do you want
//QMetaObject::invokeMethod(m_pObj,"get_right_data",Q_ARG(QString,temp),Q_ARG(int,m_id));

}

然后在主程序中通过以下开启多线程

QThreadPool *Q_pool = new QThreadPool();
Q_pool->setMaxThreadCount(1);//设置最大线程数目
Task *task = new Task();//构造任务
Q_pool->globalInstance()->start(task);//把任务加入到线程池

此处值得一提的是可以利用该函数和主函数通信传递处理结果

QMetaObject::invokeMethod(m_pObj,"get_right_data",Q_ARG(QString,temp));

m_pObj:主线程对象
get_right_data:主线程接受结果的处理函数
Q_ARG(QString,temp):传递的变量类型和变量名

需要在主线程中实现该函数

Q_INVOKABLE void get_right_data(QString msg);

*****分割线------------------------------------
3.QtConcurrent::run
最简单的方式
首先在.pro文件添加

QT += concurrent

然后添加好头文件
以下是调用的几种方式

    MyTest mc;
    //QFuture后的<>内写入函数返回的类型
    //无参数返回,传递参数
    QString str = "gg";
    QFuture<void> res = QtConcurrent::run(&mc, &MyTest::fun1,str);

    //有参数返回,无参数传递
    QFuture<bool> res1 = QtConcurrent::run(&mc, &MyTest::fun2);
    for(int i=0;i<10;i++){
        qDebug() << "hello main";
    }
    //获取线程中执行函数返回的结果
    bool testres = res1.result();
    qDebug() << "res1:" << testres ;

    //超过5个参数的调用
    MyDataInfo datainfo;
    datainfo.a1 = 1;
    datainfo.a2 = 2;
    datainfo.a3 = 3;
    datainfo.a4 = 4;
    QFuture<void> res3 = QtConcurrent::run(&mc, &MyTest::fun3,str,datainfo);

    if(!res.isFinished()){判断线程是否执行完成
        res.waitForFinished();//等待线程执行完
    }
    qDebug() << "res:" << res.isFinished();//true

*****分割线------------------------------------
心得:
在QT中使用多线程是很有必要的,和大多数界面设计一样,主线程负责UI的构建和更新,所以当你的界面出现卡顿时很有必要加入多线程。
我在进行数据解析的时候有比较耗时的数据转换操作,但是开始并没有想清楚自己线程的具体逻辑,我采取每次需要转换的时候new一个Task,将需要处理的数据通过指针传递到该线程,但是发现处理结果和数据标记号对应不上,我猜测是主线程在某个时间节点传递指针进来后开启了新线程,但是主线程继续读取其他数据,导致指针所指数据区域变化,导致子线程那边处理结果对应不上。我采用在线程被构造时马上就通过memcpy拷贝传递的指针过来也不行,还是会造成数据和数据标记号对应不上,最后采取的办法是开一个新的线程专门处理数据内容,而不是反复与主线程进行指针传递。
希望有理解原因的告知。
线程协同

全部评论

(0) 回帖
加载中...
话题 回帖

相关热帖

近期热帖

近期精华帖

热门推荐