From bbac94cc9545b32a0290e8fb2b79f23620ff2b23 Mon Sep 17 00:00:00 2001 From: rcarpa <2905943+rcarpa@users.noreply.github.com> Date: Sat, 26 Aug 2023 18:27:11 +0200 Subject: [PATCH] Use QThreadPool for torrent creation The change is in preparation for adding the possibility to create torrent files via the API. Rework TorrentCreatorThread to be a more lightweight QRunnable class. The parameters are now defined on construction time and are fixed throughout the lifecycle of the TorrentCreator. The lifecycle of the object is not bound to the one of QDialog anymore; it is now handled by the QThreadPool. This will enable easier queueing of multiple torrent creation jobs without risk of spawning many threads. PR #19500. --- src/base/CMakeLists.txt | 4 +- ...ntcreatorthread.cpp => torrentcreator.cpp} | 39 +++++++++---------- ...orrentcreatorthread.h => torrentcreator.h} | 20 ++++++---- src/gui/torrentcreatordialog.cpp | 22 ++++++----- src/gui/torrentcreatordialog.h | 5 ++- 5 files changed, 50 insertions(+), 40 deletions(-) rename src/base/bittorrent/{torrentcreatorthread.cpp => torrentcreator.cpp} (90%) rename src/base/bittorrent/{torrentcreatorthread.h => torrentcreator.h} (87%) diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index 36bb0f506..60d9995fa 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -35,7 +35,7 @@ add_library(qbt_base STATIC bittorrent/torrent.h bittorrent/torrentcontenthandler.h bittorrent/torrentcontentlayout.h - bittorrent/torrentcreatorthread.h + bittorrent/torrentcreator.h bittorrent/torrentdescriptor.h bittorrent/torrentimpl.h bittorrent/torrentinfo.h @@ -132,7 +132,7 @@ add_library(qbt_base STATIC bittorrent/speedmonitor.cpp bittorrent/torrent.cpp bittorrent/torrentcontenthandler.cpp - bittorrent/torrentcreatorthread.cpp + bittorrent/torrentcreator.cpp bittorrent/torrentdescriptor.cpp bittorrent/torrentimpl.cpp bittorrent/torrentinfo.cpp diff --git a/src/base/bittorrent/torrentcreatorthread.cpp b/src/base/bittorrent/torrentcreator.cpp similarity index 90% rename from src/base/bittorrent/torrentcreatorthread.cpp rename to src/base/bittorrent/torrentcreator.cpp index f7253f207..7762e63f8 100644 --- a/src/base/bittorrent/torrentcreatorthread.cpp +++ b/src/base/bittorrent/torrentcreator.cpp @@ -26,7 +26,7 @@ * exception statement from your version. */ -#include "torrentcreatorthread.h" +#include "torrentcreator.h" #include @@ -74,35 +74,34 @@ namespace using namespace BitTorrent; -TorrentCreatorThread::TorrentCreatorThread(QObject *parent) - : QThread(parent) +TorrentCreator::TorrentCreator(const TorrentCreatorParams ¶ms, QObject *parent) + : QObject(parent) + , m_params {params} { } -TorrentCreatorThread::~TorrentCreatorThread() -{ - requestInterruption(); - wait(); -} - -void TorrentCreatorThread::create(const TorrentCreatorParams ¶ms) -{ - m_params = params; - start(); -} - -void TorrentCreatorThread::sendProgressSignal(int currentPieceIdx, int totalPieces) +void TorrentCreator::sendProgressSignal(int currentPieceIdx, int totalPieces) { emit updateProgress(static_cast((currentPieceIdx * 100.) / totalPieces)); } -void TorrentCreatorThread::checkInterruptionRequested() const +void TorrentCreator::checkInterruptionRequested() const { if (isInterruptionRequested()) throw RuntimeError(tr("Operation aborted")); } -void TorrentCreatorThread::run() +void TorrentCreator::requestInterruption() +{ + m_interruptionRequested.storeRelaxed(1); +} + +bool TorrentCreator::isInterruptionRequested() const +{ + return m_interruptionRequested.loadRelaxed() != 0; +} + +void TorrentCreator::run() { emit updateProgress(0); @@ -225,9 +224,9 @@ void TorrentCreatorThread::run() } #ifdef QBT_USES_LIBTORRENT2 -int TorrentCreatorThread::calculateTotalPieces(const Path &inputPath, const int pieceSize, const TorrentFormat torrentFormat) +int TorrentCreator::calculateTotalPieces(const Path &inputPath, const int pieceSize, const TorrentFormat torrentFormat) #else -int TorrentCreatorThread::calculateTotalPieces(const Path &inputPath, const int pieceSize, const bool isAlignmentOptimized, const int paddedFileSizeLimit) +int TorrentCreator::calculateTotalPieces(const Path &inputPath, const int pieceSize, const bool isAlignmentOptimized, const int paddedFileSizeLimit) #endif { if (inputPath.isEmpty()) diff --git a/src/base/bittorrent/torrentcreatorthread.h b/src/base/bittorrent/torrentcreator.h similarity index 87% rename from src/base/bittorrent/torrentcreatorthread.h rename to src/base/bittorrent/torrentcreator.h index 31afeeb0c..b819306b4 100644 --- a/src/base/bittorrent/torrentcreatorthread.h +++ b/src/base/bittorrent/torrentcreator.h @@ -28,8 +28,10 @@ #pragma once +#include +#include +#include #include -#include #include "base/path.h" @@ -62,16 +64,20 @@ namespace BitTorrent QStringList urlSeeds; }; - class TorrentCreatorThread final : public QThread + class TorrentCreator final : public QObject, public QRunnable { Q_OBJECT - Q_DISABLE_COPY_MOVE(TorrentCreatorThread) + Q_DISABLE_COPY_MOVE(TorrentCreator) public: - explicit TorrentCreatorThread(QObject *parent = nullptr); - ~TorrentCreatorThread() override; + explicit TorrentCreator(const TorrentCreatorParams ¶ms, QObject *parent = nullptr); - void create(const TorrentCreatorParams ¶ms); + void run() override; + + bool isInterruptionRequested() const; + + public slots: + void requestInterruption(); #ifdef QBT_USES_LIBTORRENT2 static int calculateTotalPieces(const Path &inputPath, int pieceSize, TorrentFormat torrentFormat); @@ -86,10 +92,10 @@ namespace BitTorrent void updateProgress(int progress); private: - void run() override; void sendProgressSignal(int currentPieceIdx, int totalPieces); void checkInterruptionRequested() const; TorrentCreatorParams m_params; + QAtomicInt m_interruptionRequested; }; } diff --git a/src/gui/torrentcreatordialog.cpp b/src/gui/torrentcreatordialog.cpp index 687df05ec..749bf21d4 100644 --- a/src/gui/torrentcreatordialog.cpp +++ b/src/gui/torrentcreatordialog.cpp @@ -59,7 +59,7 @@ namespace TorrentCreatorDialog::TorrentCreatorDialog(QWidget *parent, const Path &defaultPath) : QDialog(parent) , m_ui(new Ui::TorrentCreatorDialog) - , m_creatorThread(new BitTorrent::TorrentCreatorThread(this)) + , m_threadPool(this) , m_storeDialogSize(SETTINGS_KEY(u"Size"_s)) , m_storePieceSize(SETTINGS_KEY(u"PieceSize"_s)) , m_storePrivateTorrent(SETTINGS_KEY(u"PrivateTorrent"_s)) @@ -90,13 +90,11 @@ TorrentCreatorDialog::TorrentCreatorDialog(QWidget *parent, const Path &defaultP connect(m_ui->buttonCalcTotalPieces, &QPushButton::clicked, this, &TorrentCreatorDialog::updatePiecesCount); connect(m_ui->checkStartSeeding, &QCheckBox::clicked, m_ui->checkIgnoreShareLimits, &QWidget::setEnabled); - connect(m_creatorThread, &BitTorrent::TorrentCreatorThread::creationSuccess, this, &TorrentCreatorDialog::handleCreationSuccess); - connect(m_creatorThread, &BitTorrent::TorrentCreatorThread::creationFailure, this, &TorrentCreatorDialog::handleCreationFailure); - connect(m_creatorThread, &BitTorrent::TorrentCreatorThread::updateProgress, this, &TorrentCreatorDialog::updateProgressBar); - loadSettings(); updateInputPath(defaultPath); + m_threadPool.setMaxThreadCount(1); + #ifdef QBT_USES_LIBTORRENT2 m_ui->checkOptimizeAlignment->hide(); #else @@ -233,8 +231,14 @@ void TorrentCreatorDialog::onCreateButtonClicked() , m_ui->URLSeedsList->toPlainText().split(u'\n', Qt::SkipEmptyParts) }; - // run the creator thread - m_creatorThread->create(params); + auto *torrentCreator = new BitTorrent::TorrentCreator(params); + connect(this, &QDialog::rejected, torrentCreator, &BitTorrent::TorrentCreator::requestInterruption); + connect(torrentCreator, &BitTorrent::TorrentCreator::creationSuccess, this, &TorrentCreatorDialog::handleCreationSuccess); + connect(torrentCreator, &BitTorrent::TorrentCreator::creationFailure, this, &TorrentCreatorDialog::handleCreationFailure); + connect(torrentCreator, &BitTorrent::TorrentCreator::updateProgress, this, &TorrentCreatorDialog::updateProgressBar); + + // run the torrentCreator in a thread + m_threadPool.start(torrentCreator); } void TorrentCreatorDialog::handleCreationFailure(const QString &msg) @@ -286,11 +290,11 @@ void TorrentCreatorDialog::updatePiecesCount() { const Path path = m_ui->textInputPath->selectedPath(); #ifdef QBT_USES_LIBTORRENT2 - const int count = BitTorrent::TorrentCreatorThread::calculateTotalPieces( + const int count = BitTorrent::TorrentCreator::calculateTotalPieces( path, getPieceSize(), getTorrentFormat()); #else const bool isAlignmentOptimized = m_ui->checkOptimizeAlignment->isChecked(); - const int count = BitTorrent::TorrentCreatorThread::calculateTotalPieces(path + const int count = BitTorrent::TorrentCreator::calculateTotalPieces(path , getPieceSize(), isAlignmentOptimized, getPaddedFileSizeLimit()); #endif m_ui->labelTotalPieces->setText(QString::number(count)); diff --git a/src/gui/torrentcreatordialog.h b/src/gui/torrentcreatordialog.h index 4f032c2cf..addda955d 100644 --- a/src/gui/torrentcreatordialog.h +++ b/src/gui/torrentcreatordialog.h @@ -30,8 +30,9 @@ #pragma once #include +#include -#include "base/bittorrent/torrentcreatorthread.h" +#include "base/bittorrent/torrentcreator.h" #include "base/path.h" #include "base/settingvalue.h" @@ -75,7 +76,7 @@ private: #endif Ui::TorrentCreatorDialog *m_ui = nullptr; - BitTorrent::TorrentCreatorThread *m_creatorThread = nullptr; + QThreadPool m_threadPool; // settings SettingValue m_storeDialogSize;