From 683c66d81898e1d7d4cb814a5740169529c3313e Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Mon, 19 Sep 2022 18:26:36 -0400 Subject: Scanning can now be cancelled. Fix terminate() of thread pool blocking if wait() is already called. --- qdeduper/filescanner.cpp | 26 ++++++++++++++++++++------ qdeduper/filescanner.hpp | 4 ++++ qdeduper/mingui.cpp | 23 ++++++++++++++++++----- qdeduper/mingui.hpp | 3 +++ qdeduper/sigdb_qt.cpp | 5 +++++ qdeduper/sigdb_qt.hpp | 1 + 6 files changed, 51 insertions(+), 11 deletions(-) (limited to 'qdeduper') diff --git a/qdeduper/filescanner.cpp b/qdeduper/filescanner.cpp index e7e45fc..141cfbf 100644 --- a/qdeduper/filescanner.cpp +++ b/qdeduper/filescanner.cpp @@ -6,9 +6,8 @@ using std::size_t; -FileScanner::FileScanner() : QObject(nullptr), maxmnlen(0) +FileScanner::FileScanner() : QObject(nullptr), maxmnlen(0), interrpt(false) { - } void FileScanner::add_magic_number(const std::string &m) @@ -24,9 +23,13 @@ void FileScanner::add_path(const fs::path &p, bool recurse) } template -void dirit_foreach(T iter, std::function f) +void dirit_foreach(T iter, std::function f, std::atomic *inter) { - std::for_each(fs::begin(iter), fs::end(iter), f); + for(auto &e : iter) + { + if (inter->load()) break; + f(e); + } } void FileScanner::scan() @@ -57,18 +60,29 @@ void FileScanner::scan() bool recurse; std::tie(p, recurse) = pe; if (recurse) - dirit_foreach(fs::recursive_directory_iterator(p, opt), f); + dirit_foreach(fs::recursive_directory_iterator(p, opt), f, &interrpt); else - dirit_foreach(fs::directory_iterator(p, opt), f); + dirit_foreach(fs::directory_iterator(p, opt), f, &interrpt); } }; for_all_paths(count_files); + if (interrpt.load()) return; Q_EMIT scan_done_prep(fcnt); fcnt = 0; for_all_paths(scan_file); } +void FileScanner::interrupt() +{ + interrpt.store(true); +} + +bool FileScanner::interrupted() +{ + return interrpt.load(); +} + std::vector FileScanner::file_list() { return ret; diff --git a/qdeduper/filescanner.hpp b/qdeduper/filescanner.hpp index 5d927a4..3df620e 100644 --- a/qdeduper/filescanner.hpp +++ b/qdeduper/filescanner.hpp @@ -1,6 +1,7 @@ #ifndef FILESCANNER_HPP #define FILESCANNER_HPP +#include #include #include #include @@ -16,11 +17,14 @@ class FileScanner : public QObject std::vector> paths; std::vector ret; std::size_t maxmnlen; + std::atomic interrpt; public: FileScanner(); void add_magic_number(const std::string &m); void add_path(const fs::path &p, bool recurse = false); void scan(); + void interrupt(); + bool interrupted(); std::vector file_list(); Q_SIGNALS: void scan_done_prep(std::size_t nfiles); diff --git a/qdeduper/mingui.cpp b/qdeduper/mingui.cpp index 845bc70..4e4cc87 100644 --- a/qdeduper/mingui.cpp +++ b/qdeduper/mingui.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -175,10 +176,10 @@ DeduperMainWindow::DeduperMainWindow() void DeduperMainWindow::setup_menu() { - QMenu *file = this->menuBar()->addMenu("File"); - QMenu *view = this->menuBar()->addMenu("View"); - QMenu *mark = this->menuBar()->addMenu("Marks"); - QMenu *help = this->menuBar()->addMenu("Help"); + QMenu *file = this->menuBar()->addMenu("&File"); + QMenu *view = this->menuBar()->addMenu("&View"); + QMenu *mark = this->menuBar()->addMenu("&Marks"); + QMenu *help = this->menuBar()->addMenu("&Help"); QAction *create_db = file->addAction("Create Database..."); QObject::connect(create_db, &QAction::triggered, this, &DeduperMainWindow::create_new); @@ -396,6 +397,7 @@ void DeduperMainWindow::scan_dirs(std::vector> paths) this->pd->setMaximum(0); auto f = QtConcurrent::run([this, paths] { FileScanner *fs = new FileScanner(); + this->fsc = fs; std::for_each(paths.begin(), paths.end(), [fs](auto p){fs->add_path(p.first, p.second);}); fs->add_magic_number("\x89PNG\r\n"); fs->add_magic_number("\xff\xd8\xff"); @@ -413,6 +415,12 @@ void DeduperMainWindow::scan_dirs(std::vector> paths) } }, Qt::ConnectionType::QueuedConnection); fs->scan(); + if (fs->interrupted()) + { + delete fs; + this->fsc = nullptr; + return; + } this->pd->setMaximum(fs->file_list().size() - 1); this->pd->setLabelText("Scanning..."); this->sdb = new SignatureDB(); @@ -431,8 +439,9 @@ void DeduperMainWindow::scan_dirs(std::vector> paths) this->pd->setLabelText("Finalizing..."); } }, Qt::ConnectionType::QueuedConnection); - this->sdb->scan_files(fs->file_list(), 8); + this->sdb->scan_files(fs->file_list(), std::thread::hardware_concurrency()); delete fs; + this->fsc = nullptr; }); QFutureWatcher *fw = new QFutureWatcher(this); fw->setFuture(f); @@ -442,6 +451,10 @@ void DeduperMainWindow::scan_dirs(std::vector> paths) this->curgroup = 0; this->show_group(this->curgroup); }, Qt::ConnectionType::QueuedConnection); + QObject::connect(pd, &QProgressDialog::canceled, [this] { + if (this->fsc) this->fsc->interrupt(); + if (this->sdb) this->sdb->interrupt_scan(); + }); } void DeduperMainWindow::show_group(size_t gid) diff --git a/qdeduper/mingui.hpp b/qdeduper/mingui.hpp index 94f5bbd..e4b1c3f 100644 --- a/qdeduper/mingui.hpp +++ b/qdeduper/mingui.hpp @@ -10,6 +10,7 @@ #include #include +#include "filescanner.hpp" #include "sigdb_qt.hpp" class QHBoxLayout; @@ -22,6 +23,7 @@ class QProgressDialog; class QSplitter; class QStandardItemModel; class QToolBar; +class FileScanner; class ImageItemDelegate; namespace fs = std::filesystem; @@ -42,6 +44,7 @@ private: ImageItemDelegate *id = nullptr; QProgressDialog *pd = nullptr; SignatureDB *sdb = nullptr; + FileScanner *fsc = nullptr; std::size_t curgroup; bool nohotkeywarn; diff --git a/qdeduper/sigdb_qt.cpp b/qdeduper/sigdb_qt.cpp index 692f9c7..67cc3e6 100644 --- a/qdeduper/sigdb_qt.cpp +++ b/qdeduper/sigdb_qt.cpp @@ -91,6 +91,11 @@ void SignatureDB::scan_files(const std::vector &files, int njobs) create_priv_struct(); } +void SignatureDB::interrupt_scan() +{ + if (sdb) + sdb->populate_interrupt(); +} size_t SignatureDB::num_groups() { diff --git a/qdeduper/sigdb_qt.hpp b/qdeduper/sigdb_qt.hpp index 070662d..112ffa9 100644 --- a/qdeduper/sigdb_qt.hpp +++ b/qdeduper/sigdb_qt.hpp @@ -32,6 +32,7 @@ public: bool valid(); void scan_files(const std::vector &files, int njobs); + void interrupt_scan(); size_t num_groups(); std::vector get_group(size_t gid); std::map, double> group_distances(size_t gid); -- cgit v1.2.3