Зависание программы Qt при попытке получить MD5 файлов

Привет, я использую этот код для генерации MD5 файлов в QT

QString Md5_gen(QString const &s)
{
    QString pakchunk_Md5;
    QCryptographicHash crypto(QCryptographicHash::Md5);
    QFile pakchunk("D:/Games/TDPA - Man of Medan" + s);
    if (pakchunk.open(QIODevice::ReadOnly))
    {
        while(!pakchunk.atEnd()){
        crypto.addData(pakchunk.read(8192));
        }
    } else
    {
        qDebug() << "Can't open file.";
        pakchunk_Md5 = "nofile";
        return pakchunk_Md5;
    }
    pakchunk_Md5 = crypto.result().toHex();
    return pakchunk_Md5;
}

Мне нужно сгенерировать MD5 из 8 больших файлов с этим кодом (1,5 ГБ>). Проблема в том, что когда я нажимаю кнопку, чтобы начать Генерацию MD5, замораживание графического интерфейса, пока все MD5 не сгенерировали
Im Test QFuture, QFutureWatcher, QtConcurrent таким образом, но графический интерфейс не повезло. замерзать каждый раз

main.cpp

#include "user_def.h"
#include "mainwindow2.h"
#include...

QString Md5_gen(QString const &s)
{
    QString pakchunk_Md5;
    QCryptographicHash crypto(QCryptographicHash::Md5);
    QFile pakchunk("D:/Games/TDPA - Man of Medan" + s);
    if (pakchunk.open(QIODevice::ReadOnly))
    {
        while(!pakchunk.atEnd()){
        crypto.addData(pakchunk.read(8192));
        }
    } else
    {
        qDebug() << "Can't open file.";
        pakchunk_Md5 = "nofile";
        return pakchunk_Md5;
    }
    pakchunk_Md5 = crypto.result().toHex();
    return pakchunk_Md5;
}

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

  a.setStyle(new DarkStyle);

  FramelessWindow framelessWindow;
  framelessWindow.setWindowIcon(a.style()->standardIcon(QStyle::SP_DesktopIcon));

  MainWindow *mainWindow = new MainWindow;

  framelessWindow.setContent(mainWindow);
  framelessWindow.show();

  return a.exec();
}


user_def.h

#ifndef USER_DEF_H
#define USER_DEF_H
#include <QString>

QString Md5_gen(QString const &s);

#endif // USER_DEF_H


mainwindow2.h

#ifndef MAINWINDOW2_H
#define MAINWINDOW2_H

#include <QMainWindow>
#include <QtConcurrentRun>
#include <QFuture>
#include <QFutureWatcher>
#include <QThread>
#include <QThreadPool>
#include "user_def.h"

namespace Ui {
class MainWindow2;
}

class MainWindow2 : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow2(QWidget *parent = nullptr);
    ~MainWindow2();

public slots:
      void run_thread();
      void displayFinishedBox();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow2 *ui;
    QFutureWatcher<QString> *watcher;
    QFuture<QString> *future;
};

#endif // MAINWINDOW2_H


mainwindow2.cpp

#include...

MainWindow2::MainWindow2(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow2)
{
    ui->setupUi(this);
    connect(ui->pushButton, &QPushButton::clicked,
               this, &MainWindow2::run_thread);


    // display a message box when the calculation has finished

    future = new QFuture<QString>;
    watcher = new QFutureWatcher<QString>;

    connect(watcher, SIGNAL(finished()),
            this, SLOT(displayFinishedBox()));

}

MainWindow2::~MainWindow2()
{
    delete ui;
}

void MainWindow2::run_thread()
{
    int file_ok = 0;
    //file pak33
    QString loc33 = "/SM/test1.pak";
    QFuture<QString> future33 = QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc33);
    watcher->setFuture(future33);
    QString pakchunk33 = future33.result();

    qDebug() << pakchunk33;
    if (pakchunk33 == "f7002d4419cd235a87746715ba6fb2ea")
    {
        qDebug() << "OK";
        file_ok++;
        ui->label_8->setText("OK");
        ui->label_8->setStyleSheet("QLabel { color : green; }");
    } else if (pakchunk33 == "nofile")
    {
        qDebug() << "no file found";
        ui->label_8->setText("not found");
        ui->label_8->setStyleSheet("QLabel { color : red; }");
    } else
    {
        qDebug() << "file is diffrent";
        ui->label_8->setText("wrong");
        ui->label_8->setStyleSheet("QLabel { color : red; }");
    }
    ui->progressBar->setValue(12);

    //file pak34
    QString loc34 = "/SM/test2.pak";
    QFuture<QString> future34 = QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc34);
    watcher->setFuture(future34);
    QString pakchunk34 = future34.result();
    qDebug() << pakchunk34;

    if (pakchunk34 == "64c77598586b6c3cb60beed0b0750620")
    {
        qDebug() << "OK";
        file_ok++;
        ui->label->setText("OK");
        ui->label->setStyleSheet("QLabel { color : green; }");
    } else if (pakchunk34 == "nofile")
    {
        qDebug() << "no file found";
        ui->label->setText("not found");
        ui->label->setStyleSheet("QLabel { color : red; }");
    } else
    {
        qDebug() << "file is diffrent";
        ui->label->setText("wrong");
        ui->label->setStyleSheet("QLabel { color : red; }");
    }
    ui->progressBar->setValue(25);

    //file pak35
    QString loc35 = "/SM/test3.pak";
    QFuture<QString> future35 = QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc35);
    watcher->setFuture(future35);
    QString pakchunk35 = future35.result();

    qDebug() << pakchunk35;
    if (pakchunk35 == "ee53f7a7656a32b5278c460baec46f16")
    {
        qDebug() << "OK";
        file_ok++;
        ui->label_7->setText("OK");
        ui->label_7->setStyleSheet("QLabel { color : green; }");
    } else if (pakchunk35 == "nofile")
    {
        qDebug() << "no file found";
        ui->label_7->setText("not found");
        ui->label_7->setStyleSheet("QLabel { color : red; }");
    } else
    {
        qDebug() << "file is diffrent";
        ui->label_7->setText("wrong");
        ui->label_7->setStyleSheet("QLabel { color : red; }");
    }
    ui->progressBar->setValue(38);

    /*Some other code*/

Кто-нибудь может сказать, в чем моя проблема и как я могу ее исправить?

редактировать 1

Я редактирую свой код таким образом, чтобы он работал хорошо без зависания графического интерфейса с точки зрения кодирования, этот код является стандартным?

mainwindow2.cpp

MainWindow2::MainWindow2(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow2)
{
    ui->setupUi(this);
    connect(ui->pushButton_3, &QPushButton::clicked, this, &MainWindow2::MD5_thread_1);

    future = new QFuture<QString>;
    watcher1 = new QFutureWatcher<QString>;
    watcher2 = new QFutureWatcher<QString>;
    watcher3 = new QFutureWatcher<QString>;

    connect(watcher1, &QFutureWatcher<QString>::finished, this, &MainWindow2::MD5_thread_2);
    connect(watcher2, &QFutureWatcher<QString>::finished, this, &MainWindow2::MD5_thread_3);
    connect(watcher3, &QFutureWatcher<QString>::finished, this, &MainWindow2::MD5_thread_4);
    //some other code
}

void MainWindow2::MD5_thread_1()
{
    ui->pushButton->setEnabled(false);
    ui->pushButton->setText("procces started");
    ui->pushButton->setStyleSheet("QPushButton { color : white; background-color: rgb(73, 80, 93); }");
    ui->label->setText("checking");
    ui->label_2->setText("checking");
    ui->label_3->setText("checking");
    ui->label_4->setText("checking");
    ui->label_5->setText("checking");
    ui->label_6->setText("checking");
    ui->label_7->setText("checking");
    ui->label_8->setText("checking");
    ui->label_14->setText("waiting for end of check");
    ui->progressBar->setRange(0, 100);
    ui->progressBar_2->setRange(0, 100);
    ui->progressBar->setValue(0);
    ui->progressBar_2->setValue(0);

    //file pak33
    QString loc33 = "/SMG0/editor.pak";
    *future= QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc33);
    watcher1->setFuture(*future);
}

void MainWindow2::MD5_thread_2()
{
    QString pakchunk33 = future->result();

    qDebug() << pakchunk33;
    if (pakchunk33 == "f7002d4419cd235a87746715ba6fb2ea")
    {
        qDebug() << "OK";
        file_ok++;
        ui->label_8->setText("OK");
        ui->label_8->setStyleSheet("QLabel { color : green; }");
    } else if (pakchunk33 == "nofile")
    {
        qDebug() << "no file found";
        ui->label_8->setText("not found");
        ui->label_8->setStyleSheet("QLabel { color : red; }");
    } else
    {
        qDebug() << "file is diffrent";
        ui->label_8->setText("wrong");
        ui->label_8->setStyleSheet("QLabel { color : red; }");
    }
    ui->progressBar->setValue(12);
    watcher1->deleteLater();

    //file pak34
    QString loc34 = "/SMG0/2Editor.pak";
    *future = QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc34);
    watcher2->setFuture(*future);
}

void MainWindow2::MD5_thread_3()
{
    QString pakchunk34 = future->result();
    qDebug() << pakchunk34;

    if (pakchunk34 == "64c77598586b6c3cb60beed0b0750620")
    {
        qDebug() << "OK";
        file_ok++;
        ui->label->setText("OK");
        ui->label->setStyleSheet("QLabel { color : green; }");
    } else if (pakchunk34 == "nofile")
    {
        qDebug() << "no file found";
        ui->label->setText("not found");
        ui->label->setStyleSheet("QLabel { color : red; }");
    } else
    {
        qDebug() << "file is diffrent";
        ui->label->setText("wrong");
        ui->label->setStyleSheet("QLabel { color : red; }");
    }
    ui->progressBar->setValue(25);
    watcher2->deleteLater();

    //file pak35
    QString loc35 = "/SMG0/3Editor.pak";
    *future = QtConcurrent::run(QThreadPool::globalInstance(), Md5_gen, loc35);
    watcher3->setFuture(*future);
}


void MainWindow2::core_install
{
    QString pakchunk35 = future->result();

    qDebug() << pakchunk40;
    if (pakchunk40 == "49e0440340044f424caeb82bade1301f")
    {
        qDebug() << "OK";
        file_ok++;
        ui->label_2->setText("OK");
        ui->label_2->setStyleSheet("QLabel { color : green; }");
    } else if (pakchunk40 == "nofile")
    {
        qDebug() << "no file found";
        ui->label_2->setText("not found");
        ui->label_2->setStyleSheet("QLabel { color : red; }");
    } else
    {
        qDebug() << "file is diffrent";
        ui->label_2->setText("wrong");
        ui->label_2->setStyleSheet("QLabel { color : red; }");
    }
    ui->progressBar->setValue(100);
    watcher3->deleteLater();

    //check if game is okey or not
    if (file_ok == 8)
    {
        ui->label_14->setText("O");
        ui->label_14->setStyleSheet("QLabel { color : green; }");
    } else
    {
        ui->label_14->setText("X");
        ui->label_14->setStyleSheet("QLabel { color : red; }");
    }
}

mainwindow2.h

#ifndef MAINWINDOW2_H
#define MAINWINDOW2_H

#include <QMainWindow>
#include <QtConcurrentRun>
#include <QFuture>
#include <QFutureWatcher>
#include <QThread>
#include <QThreadPool>
#include "user_def.h"

namespace Ui {
class MainWindow2;
}

class MainWindow2 : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow2(QWidget *parent = nullptr);
    ~MainWindow2();

public slots:
      void MD5_thread_1();
      void MD5_thread_2();
      void MD5_thread_3();
      void core_install();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void on_radioButton_2_clicked();

    void on_radioButton_4_clicked();

    void on_radioButton_3_clicked();

    void on_radioButton_clicked();

private:
    Ui::MainWindow2 *ui;
    QFutureWatcher<QString> *watcher1;
    QFutureWatcher<QString> *watcher2;
    QFutureWatcher<QString> *watcher3;
    QFuture<QString> *future;
    int file_ok = 0;
};

#endif // MAINWINDOW2_H

1 ответ

Решение

В result блокирует ваш поток пользовательского интерфейса, делая бесполезным весь параллельный / будущий танец.

Создайте наблюдателя на будущее и свяжите его finished сигнал лямбда, который передает как имя файла, так и содержимое результата в onHashCalculatedв вашем окне. В этом методе вы можете проверить, соответствует ли хеш одному из ваших предопределенных хешей, и обновить пользовательский интерфейс.

Или переместите текущий run_thread функцию в отдельный QObject, который выполняется в отдельном потоке, и пусть он испускает hashCalculated(name, hash) сигнализировать, что ваше главное окно подписано на использование onHashCalculated слот, аналогичный описанному выше.

Вот код для HashChecker, который инкапсулирует оба подхода.

Обратите внимание на статический QMap который отображает имена файлов в хеши, способ doneFile прикован к checkDone.

enum class Status { Ok, NotOk, Missing };

class HashChecker : public QObject {
    Q_OBJECT

public:
    QMap<QString, Status> done;

    HashChecker(QObject *parent = nullptr) : QObject(parent) {
        QObject::connect(this, &HashChecker::doneFile, this, &HashChecker::checkDone);
    }

    inline static const QMap<QString, QString> hashes = {
        {"/SM/test1.pak", "f7002d4419cd235a87746715ba6fb2ea"},
        {"/SM/test2.pak", "64c77598586b6c3cb60beed0b0750620"},
        {"/SM/test3.pak", "ee53f7a7656a32b5278c460baec46f16"},
    };

signals:
    void finished();
    void doneFile(const QString& fname, Status s);

private slots:
    void checkDone(const QString& fname, Status s) {
        done[fname] = s;
        if (done.size() == hashes.size())
            emit finished();
    }

public slots:
    void check_parallel() {
        for (auto it = hashes.cbegin(); it != hashes.cend(); it++) {
            auto fname = it.key();
            auto hash = it.value();

            QFuture<Status> fut = QtConcurrent::run(do_hash, fname, hash);
            QFutureWatcher<Status> *fw = new QFutureWatcher<Status>(this);
            fw->setFuture(fut);
            QObject::connect(fw, &QFutureWatcher<Status>::finished, this,
                    [=]() {
                    fw->deleteLater();
                    emit doneFile(fname, fut.result());
            });
        }
    }

    void check_sequential() {
        for (auto it = hashes.cbegin(); it != hashes.cend(); it++) {
            auto fname = it.key();
            auto hash = it.value();

            auto result = do_hash(fname, hash);
            emit doneFile(fname, result);
        }
    }
};

Если вы хотите проверять файлы параллельно:

HashChecker *hc = new HashChecker();
QObject::connect(hc, &HashChecker::doneFile, this, &MainWindow2::onHashCalculated);
hc->check_parallel();

Последовательность в другом потоке почти такая же:

QThread *t = new QThread(this);
HashChecker *hc = new HashChecker();
hc->moveToThread(t);
QObject::connect(t, &QThread::started, hc, &HashChecker::check_sequential);
QObject::connect(hc, &HashChecker::doneFile, this, &MainWindow2::onHashCalculated);
QObject::connect(hc, &HashChecker::finished, t, &QThread::quit);
t->start();
Другие вопросы по тегам