简体   繁体   English

如何停止对 QThread 的长时间操作?

[英]How to stop long operation on QThread?

I've made some research but I couldn't find the answer to why my solution is not working.我做了一些研究,但找不到我的解决方案为何不起作用的答案。 But to the point.但说到点子上。

I've got QWidget as a separate dialog in my app.我在我的应用程序中将 QWidget 作为单独的对话框。 I'm using this QWidget class to gather paths to files and zip them into one file with ZipLib.我正在使用这个 QWidget class 来收集文件的路径,并将它们 zip 通过 ZipLib 收集到一个文件中。 To give users some feedback about the progress of the zipping I've added QProgressBar which is updated during zipping.为了向用户提供有关压缩进度的一些反馈,我添加了 QProgressBar,它会在压缩过程中更新。 But I've found out that in some cases when files are too big, zipping files are taking very long and makes my app not respond during this time.但我发现,在某些情况下,当文件太大时,压缩文件会花费很长时间,导致我的应用程序在此期间无法响应。 So my idea was to move the long operation of zipping to another thread using QThread and everything is working fine, zipping is working, and the progress bar is updated BUT there is a problem when I want to cancel the zipping operation.所以我的想法是使用 QThread 将长时间的压缩操作移至另一个线程,一切正常,压缩工作正常,进度条已更新但是当我想取消压缩操作时出现问题。 With my current approach action with zipping just don't listen to any of my requests to interrupt the thread and the thread is doing zipping even after I've closed my dialog.使用我当前的压缩方法操作只是不听我的任何中断线程的请求,即使在我关闭对话框后线程仍在进行压缩。 I'll show you my approach maybe there is something very trivial but I just can't make to cancel this zipping operation.我会告诉你我的方法,也许有一些非常微不足道的事情,但我无法取消这个压缩操作。

tl;dr version: I can't interrupt QThread with requestInterruption() or any other way. tl;dr 版本:我不能用requestInterruption()或任何其他方式中断 QThread。

This is my WorkerThread class:这是我的 WorkerThread class:

class WorkerThread : public QThread
{
Q_OBJECT

public:
    void setup(std::string zip, std::vector<std::string> file)
    {
        mZip = zip;
        mFiles = file;
        mActionStopped = false;
    }

    void run() override {
        size_t progressValue = (100 / mFiles.size());

        try
        {
            for (const auto& file : mFiles)
            {
                if (not isInterruptionRequested())
                {
                    Q_EMIT updateTheProgress(progressValue);
                    ZipFile::AddFile(mZip, file);
                }
                else
                {
                    return;
                }
            }
        }
        catch(const std::exception& e)
        {
            Q_EMIT resultReady(false);
        }

        if (not mActionStopped)
        {
            Q_EMIT updateTheProgress(100 - actualProgress); // To set 100%
            Q_EMIT resultReady(true);
        }
    }

    std::string mZip;
    std::vector<std::string> mFiles;
    size_t actualProgress = 0;
    bool mActionStopped;

Q_SIGNALS:
    void resultReady(bool dupa);
    void updateProgress(int value);

public Q_SLOTS:
    void updateTheProgress(int value)
    {
        actualProgress += value;
        Q_EMIT updateProgress(actualProgress);
    }

    void stopWork()
    {
        mActionStopped = true;
    }
};

And in my QWidget class I've got something like this:在我的 QWidget class 中,我有这样的东西:

workerThread = new WorkerThread();
connect(workerThread, &WorkerThread::resultReady, this, &ZipProjectDialog::zipDone);
connect(workerThread, SIGNAL(updateProgress(int)), progressBar, SLOT(setValue(int)));

connect(btnBox, &QDialogButtonBox::rejected, workerThread, &WorkerThread::requestInterruption);
connect(btnBox, &QDialogButtonBox::rejected, workerThread, &WorkerThread::stopWork);

workerThread->setup(zipFilename, filePathList);
workerThread->start();
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);

I've followed QThread documentation with this but requestInterruption() is still not working.我已经遵循了QThread文档,但requestInterruption()仍然无法正常工作。

If someone has any idea how to resolve this I'll appreciate it.如果有人知道如何解决这个问题,我将不胜感激。

Thanks!谢谢!

You cannot interrupt the execution of你不能中断执行

ZipFile::AddFile(mZip, file);

itself.本身。 It is a single call to a function, and no one checks isInterruptionRequested() inside that function.这是对 function 的一次调用,没有人检查 function 中的isInterruptionRequested()

A simplified example一个简化的例子

#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>

class MyThread : public QThread
{
public:
    void run() override
    {
        qDebug() << "starting";
        for (int i = 0; i < 10; ++i) {
            qDebug() << "loop" << i;
            if (!isInterruptionRequested())
                sleep(5);
            else
                break;
        }
        qDebug() << "finished";
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    MyThread thread;
    QTimer::singleShot(0, &thread, [&thread] {
        thread.start();
        QTimer::singleShot(7000 /*7 seconds*/, &thread, [&thread] {
            qDebug() << "interrupting";
            thread.requestInterruption();
        });
    });

    return a.exec();
}

prints印刷

starting
loop 0
loop 1
interrupting
loop 2
finished

as expected.正如预期的那样。 And as expected there are a few seconds delay between "interrupting" and "loop 2", and no delay between "loop 2" and "finished".正如预期的那样,“中断”和“循环 2”之间有几秒钟的延迟,“循环 2”和“完成”之间没有延迟。

If you want to interrupt your task more granular, then you have to find a more granular API than ZipFile::AddFile, so you can check isInterruptionRequested() regularly even while a single file is archived, or use an external process that can be killed instead.如果你想更细粒度地中断你的任务,那么你必须找到一个比 ZipFile::AddFile 更细粒度的 API,这样你就可以定期检查isInterruptionRequested()即使在单个文件被归档时,或者使用可以被杀死的外部进程反而。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM