Qt C++子线程中执行任务队列

版权声明:支持原创,转载请说明~ https://blog.csdn.net/luoyayun361/article/details/88974834

概述

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

示例

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

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

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

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

    bool saveImage();
    QString path();
private:
    QImage m_image;             //将要保存的图片
    QString m_strSavePath;      //保存地址
};
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;
}

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

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;
};
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;
}

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

然后再看如何调用:

    m_pSaveCore = new ImageSaveCore(this);
    m_pSaveCore->start();
    /*
     ...
     
     */ 
    m_pSaveCore->addTask(new Task(image,"xxx"));

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

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

猜你喜欢

转载自blog.csdn.net/luoyayun361/article/details/88974834