Qt C++子线程中执行任务队列(转载)

 

转自:https://luoyayun361.blog.csdn.net/article/details/88974834

概述

在项目中经常会遇到这种情况,当要执行一些耗时操作的时候,如果是在主线程中进行,将会导致界面阻塞,整体体验就会很差,那么,这种情况通常会将任务扔到子线程中去执行。那如果说需要执行的这些任务很多,这时候就需要将任务放到一个队列中,然后循环在子线程中执行任务。所以,这里来介绍一下该场景的框架设计,如何在子线程中执行耗时任务队列。

示例

上面的描述可能不是很好理解,接下来看一个实际的用例。

假如,我们要保存很多高清图片到本地,由于保存动作是比较耗时的,然后由于数量较多,我们将需要保存的任务封装起来交给线程中去一个个执行。所以接下来看看代码的设计:

首先创建一个任务类,用于管理该任务的所有信息:

// 单个任务类
class Task
{
public:
    Task(QImage image,QString path);

    bool saveImage();
    QString path();
private:
    QImage m_image;             //将要保存的图片
    QString m_strSavePath;      //保存地址
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
Task::Task(QImage image, QString path):
    m_image(image),
    m_strSavePath(path)
{
}

bool Task::saveImage()
{
    bool ret = false;
    if(!m_image.isNull() && !m_strSavePath.isEmpty()){
        ret = m_image.save(m_strSavePath);
    }
    return ret;
}

QString Task::path()
{
    return m_strSavePath;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

然后创建线程 用于执行任务列表:

class ImageSaveCore : public QThread
{
    Q_OBJECT
public:
    ImageSaveCore(QObject * parent = nullptr);
    void run();
    void addTask(Task * task); //添加任务,在最前面添加,保证最后添加的优先级最高
    Task * popTask();
    void stop(){m_bStart = false;}

signals:
    void sigImgSaveFinish(QString path); //图片保存完成
private:
    QList<Task *> m_taskList;  //任务列表
    QMutex m_mutex;
    bool m_bStart = true;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
ImageSaveCore::ImageSaveCore(QObject * parent):
    QThread (parent)
{
}

void ImageSaveCore::run()
{
    while (m_bStart) {
        Task * task = popTask();
        if(task){
            if(task->saveImage()){
                emit sigImgSaveFinish(task->path());
                delete task;
                task = nullptr;
            }
        }
        msleep(10);
    }
}

void ImageSaveCore::addTask(Task *task)
{
    m_mutex.lock();
    m_taskList.push_front(task);
    m_mutex.unlock();
}

Task *ImageSaveCore::popTask()
{
    m_mutex.lock();
    Task * task;
    if(m_taskList.size() == 0){
        task =  nullptr;
    }
    else{
        task = m_taskList.takeFirst();
    }
    m_mutex.unlock();
    return task;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

可以看到,添加任务直接调用addTask,将封装好的任务添加到列表中去,然后在 run中会一直循环执行任务队列。只要有任务进来就会自动执行,并且在执行完后会自动删除任务。

然后再看如何调用:

    m_pSaveCore = new ImageSaveCore(this);
    m_pSaveCore->start();
    /*
     ...
     
     */ 
    m_pSaveCore->addTask(new Task(image,"xxx"));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这里为了方便,就只列出了添加任务的方式,其中 image 就是内存中需要保存到本地的图片,xxx 就是要保存的完整路径(包含文件名)。最后析构的时候记得关闭线程。就不多介绍了。

OK, 以上的结构就是介绍如何在线程中执行这种任务队列,不影响主线程的执行,其实这种方式在项目中使用得挺多,可以直接根据该结构去进行扩展即可。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值