Download updater thread works via a queue

Made the download updater thread process requests from a queue.

Such a scheme paves the path to performing all download actions
asynchronously by placing them onto the queue (which will eliminate
non-responsiveness of the application when those commands hit the
problem with slow responses from aria2c).
This commit is contained in:
Veloman Yunkan 2024-06-04 16:15:03 +04:00 committed by Kelson
parent 03c45e814b
commit 9defd359a6
2 changed files with 63 additions and 4 deletions

View File

@ -79,6 +79,10 @@ DownloadManager::~DownloadManager()
{ {
QThread* t = mp_downloadUpdaterThread; QThread* t = mp_downloadUpdaterThread;
mp_downloadUpdaterThread = nullptr; // tell the thread to terminate mp_downloadUpdaterThread = nullptr; // tell the thread to terminate
// At this point the thread may be stuck waiting for data.
// Let's wake it up.
m_requestQueue.enqueue("");
t->wait(); t->wait();
} }
} }
@ -88,20 +92,36 @@ bool DownloadManager::downloadingFunctionalityAvailable() const
return mp_downloader != nullptr; return mp_downloader != nullptr;
} }
void DownloadManager::processDownloadActions()
{
while ( mp_downloadUpdaterThread != nullptr ) {
const QString bookId = m_requestQueue.dequeue();
if ( !bookId.isEmpty() ) {
updateDownload(bookId);
}
}
}
void DownloadManager::startDownloadUpdaterThread() void DownloadManager::startDownloadUpdaterThread()
{ {
// so that DownloadInfo can be copied across threads // so that DownloadInfo can be copied across threads
qRegisterMetaType<DownloadInfo>("DownloadInfo"); qRegisterMetaType<DownloadInfo>("DownloadInfo");
mp_downloadUpdaterThread = QThread::create([=]() { mp_downloadUpdaterThread = QThread::create([=]() {
while ( mp_downloadUpdaterThread != nullptr ) { processDownloadActions();
});
mp_downloadUpdaterThread->start();
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, [this]() {
if ( m_requestQueue.isEmpty() ) {
for ( const auto& bookId : m_downloads.keys() ) { for ( const auto& bookId : m_downloads.keys() ) {
updateDownload(bookId); m_requestQueue.enqueue(bookId);
} }
QThread::msleep(1000);
} }
}); });
mp_downloadUpdaterThread->start(); timer->start(1000);
} }
void DownloadManager::restoreDownloads() void DownloadManager::restoreDownloads()

View File

@ -5,8 +5,10 @@
#include <QMap> #include <QMap>
#include <QMutex> #include <QMutex>
#include <QMutexLocker> #include <QMutexLocker>
#include <QQueue>
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
#include <QWaitCondition>
#include <chrono> #include <chrono>
#include <memory> #include <memory>
@ -17,6 +19,38 @@
typedef QMap<QString, QVariant> DownloadInfo; typedef QMap<QString, QVariant> DownloadInfo;
template<class T>
class ThreadSafeQueue
{
public:
void enqueue(const T& x)
{
const QMutexLocker threadSafetyGuarantee(&m_mutex);
m_queue.enqueue(x);
m_queueIsNotEmpty.wakeAll();
}
T dequeue()
{
const QMutexLocker threadSafetyGuarantee(&m_mutex);
if ( m_queue.isEmpty() )
m_queueIsNotEmpty.wait(&m_mutex);
return m_queue.dequeue();
}
bool isEmpty() const
{
const QMutexLocker threadSafetyGuarantee(&m_mutex);
return m_queue.isEmpty();
}
private: // data
mutable QMutex m_mutex;
QQueue<T> m_queue;
QWaitCondition m_queueIsNotEmpty;
};
class DownloadState class DownloadState
{ {
public: // types public: // types
@ -114,7 +148,11 @@ signals:
void downloadUpdated(QString bookId, const DownloadInfo& ); void downloadUpdated(QString bookId, const DownloadInfo& );
void downloadDisappeared(QString bookId); void downloadDisappeared(QString bookId);
private: // types
typedef ThreadSafeQueue<QString> RequestQueue;
private: // functions private: // functions
void processDownloadActions();
void updateDownload(QString bookId); void updateDownload(QString bookId);
private: // data private: // data
@ -122,6 +160,7 @@ private: // data
kiwix::Downloader* const mp_downloader; kiwix::Downloader* const mp_downloader;
Downloads m_downloads; Downloads m_downloads;
QThread* mp_downloadUpdaterThread = nullptr; QThread* mp_downloadUpdaterThread = nullptr;
RequestQueue m_requestQueue;
}; };
#endif // DOWNLOADMANAGEMENT_H #endif // DOWNLOADMANAGEMENT_H