0

我有一个对象的初始化任务,这很长。正确的方法是什么?

这是我到目前为止的代码(为简单起见,初始化仅包括将条目添加到字符串列表):

#ifndef TASKINITIALIZER_H
#define TASKINITIALIZER_H
#include <QDir>
#include <QThread>
#include <QObject>
#include "task.h"
class TaskInitializer:public QThread
{
    Q_OBJECT
    QDir dir;
    QString msg;
    Task &result;
public:
    TaskInitializer(QString dname, bool png, bool jpg, bool bmp, Task &res);
    ~TaskInitializer();
    const QString& getMessage();
    bool isOk();
private:
    void run();

};

#endif // TASKINITIALIZER_H


#include <QDir>
#include <QDirIterator>
#include "taskinitializer.h"

TaskInitializer::TaskInitializer(QString dname, bool png, bool jpg, bool bmp, Task & res):
    dir(dname),result(res)
{
    QStringList filters;
    if (png)
        filters << "*.png";
    if(jpg)
    {
        filters << "*.jpeg" << "*.jpg";
    }
    if(bmp)
        filters << "*.bmp";
    dir.setNameFilters(filters);
}

TaskInitializer::~TaskInitializer()
{
}

const QString &TaskInitializer::getMessage()
{
    return msg;
}


bool TaskInitializer::isOk()
{
    if (!dir.exists())
    {
        msg = ("Directory does not exist");
        return false;
    }
    if (dir.nameFilters().length() < 1)
    {
        msg = ("No image types chosen");
        return false;
    }
    return true;
}

void TaskInitializer::run()
{
    QDirIterator di(dir,QDirIterator::Subdirectories);
    while(di.hasNext())
    {
        result.addFilename(di.next());
    }
}

ide 是将参数传递给构造函数中的初始化实例,检查它们的有效性,然后运行初始化本身。但是,初始化可能需要很长时间,并且应用程序可能会突然停止;在这种情况下,初始化程序应正确停止其活动并进行清理。

我已经阅读了几种运行异步任务的方法,但仍然不明白如何检测停止信号。据我所见,在线程池中运行 QRunnable 或使用 QtConcurrent::run() 并没有提供任何检查是否该停止的机制。

另外,我对如何将正在初始化的对象正确地传入和传出初始化任务的主题感到困惑,这样可以保证将其清理干净。与初始化程序相同;怎么保证清理干净?

这是我目前用来启动初始化的代码:

_temp = new Task();
TaskInitializer *worker = new TaskInitializer(_directoryName,flags[2],flags[1],flags[0],*_temp);
if (!worker->isOk())
{
    delete _temp;
    _temp = NULL;
    emit logMessage(worker->getMessage());
    return _temp;
}

//clearTempTask();
emit logMessage("New task created");
connect(worker,SIGNAL(finished()),SIGNAL(taskInitialized()));
connect(worker,SIGNAL(finished()),worker,SLOT(deleteLater()));
worker->start();
worker = NULL;
4

1 回答 1

0

好吧,快速而简单的方法是有一个布尔变量(命名为 pleaseStop 或其他东西),初始化程序线程不时检查它以查看主线程是否已将其设置为 true。如果主线程已将其设置为 true,则线程任务将看到它并中止其初始化例程并退出。

一个更好的方法是将初始化任务分解成更小的部分——例如做 50 毫秒的初始化,然后如果还有更多的初始化要做,调用 QTimer::singleShot(0, this, SLOT(DoSomeMore( )) 并从该方法返回,这样 DoSomeMore() 插槽在 Qt 事件循环的下一次迭代中被调用,但同时任何其他挂起的信号(例如来自主的 PleaseQuitNow() 类型的信号可以连接到 QThread 的 quit() 插槽的线程)将被处理。

事实上,如果你将时间片保持得足够短,使用第二种方法,你甚至可能根本不需要启动第二个线程——初始化可以在主线程中运行,但 GUI 事件仍会以相对及时的方式得到服务,因为它们会穿插在简短的 DoSomeMore() 调用之间,而不是被一个非常冗长的 DoEverythingAllInOneGo() 调用阻塞。

至于来回传递数据对象,只需向初始化线程传递一个指向数据对象的指针/引用就足够了,只要您小心确保以下内容:

  1. 在初始化线程完成其工作之前,主线程不应读取或写入数据对象
  2. 主线程必须保证数据对象在初始化线程完成其工作之前保持有效(例如,当初始化线程可能仍在使用它时,不要删除数据对象!)
于 2013-06-07T06:41:53.853 回答